Hi Felipe,
Thanks for your efforts !
There are quite some issues here i'd like to mention :
- Just like Impact does, you are polluting the Array prototype with enumerable methods that prevents to do a for..in. You have to use Object.defineProperty to avoid that. Bonus is that you can simplify the function getAssociativeArrayLength to function() { return this.length; } :-)
- you have a lot of redundant code to check/throw method.
- Two names seems misleading. I suggest :
first --> skipFirst
last --> skipLast
- Behaviour of first/last when called with no args seems very strange.
- You create tons of garbage in quite some methods. Rotate is a nightmare. Remember garbage is your enemy, Impact's framerate drop are caused by too many L0/L1 garbage created by collision/map collision/input/other parts of the lib. So avoid making things worse !!! :-)
- use the 'goods' methods of the array whenever you can (slice is good for example, when splice is not).
You might be interested in having a look at my post on arrays :
http://gamealchemist.wordpress.com/2013/05/01/lets-get-those-javascript-arrays-to-work-fast/
Here's your code after some refactoring, !!!! i did not test it !!! but hopefully it'll help you write clearer, faster, garbage free code.
// !!! Untested code, provided for the discussion, do not use in your code !!!!
'use strict';
(function () {
var newArrayMethods = {
/**
* Returns a shallow copy of this array
*/
copy: function () {
return this.slice(0);
},
/**
* Returns true if this array contains 'element', returns false otherwise
*/
contains: function (element) {
return this.indexOf(element) >= 0 ;
},
/**
* Returns a copy of this array, removing the elements
* 'from' index 'to' index within it
*/
remove: function (from, to) {
var res = [];
var i = 0,
j = 0;
for (i = 0; i < from; i++) {
res[i] = this[i];
}
j = i;
for (i = to; i < this.length; i++) {
res[j++] = this[i];
}
return res;
},
/**
* Returns a copy of this array, rotated 'n' places,
* counterclockwise if 'n' is positive, clockwise otherwise
*/
rotate: function (n) {
if (!n) return this.slice(0);
var length = this.length;
var res = new Array(length);
var thisIndex = (n > 0) ? n : length + n,
i = 0,
j = 0;
for (i = thisIndex; i < length; i++) {
res[j++] = this[i];
}
for (i = 0; i < thisIndex; i++) {
res[j++] = this[i];
}
return res;
},
/**
* Returns a copy of this array, removing but
* the first 'n' elements from it
* assumes n=1 when called with no arguments.
*/
skipFirst: function (n) {
if (n === 'undefined') n = 1;
return this.slice(n);
},
/**
* Returns a copy of this array, removing
* but the last 'n' elements from it
* assumes n=1 when called with no arguments.
*/
skipLast: function (n) {
if (n === 'undefined') n = 1;
if (n > this.length) return [];
return this.slice(0, this.length - n);
},
/**
* Returns a copy of this array,
* sorting its elements randomly
*/
shuffle: function () {
var copy = this.slice(0);
return copy.sort(function () {
return Math.random() - 0.5;
});
},
/**
* Returns this associative array length
*/
getAssociativeArrayLength: function () {
return this.length;
},
/**
* Returns a copy of this array that contains the difference
* between source array and 'array'
*/
difference: function (array) {
var filterFunc = filterOnOtherArray_diff.bind(array);
return this.filter(filterFunc);
},
/**
* Returns a copy of this array that contains the
* intersection between source array and 'array'
*/
intersection: function (array) {
var filterFunc = filterOnOtherArray_inter.bind(array);
return this.filter(filterFunc);
},
/**
* Returns a copy of this array that contains the union
* between source array with 'array', removing duplicates
* ! fails with a sparse array !
*/
union: function (array) {
var obj = {},
res = [],
i = 0,
k = 0;
for (i = 0; i < this.length; i++) {
obj[this[i]] = this[i];
}
for (i = 0; i < array.length; i++) {
obj[array[i]] = array[i];
}
for (k in obj) {
res.push(obj[k]);
}
return res;
}
}
// let's install those methods on the prototype
for (var newMethodName in newArrayMethods) {
installFunction(newMethodName, newArrayMethods[newMethodName]);
}
function installFunction(name, fn) {
if (Array.prototype[name]) throw ('Array method ' + name + '() already defined.');
Object.defineProperty(Array.prototype, name, {
value: fn
});
}
function filterOnOtherArray_diff(arr, i) {
return (arr.indexOf(i) < 0);
}
function filterOnOtherArray_inter(arr, i) {
return (arr.indexOf(i) >= 0);
}
})();