Permalink
Browse files

Avoid calling Array.prototype ES5 natives and fixes some edge-cases. c…

…loses #57

Squashed commit of the following:

commit 9a5261c
Author: millermedeiros <miller@millermedeiros.com>
Date:   Sat Aug 11 00:09:32 2012 -0300

    moar tests for filter

commit 2ea1c17
Author: millermedeiros <miller@millermedeiros.com>
Date:   Thu Jul 26 14:03:16 2012 -0300

    improve array/forEach spec for sparse arrays and add notes about edge cases. see #gh-57

commit cad78a7
Author: millermedeiros <miller@millermedeiros.com>
Date:   Thu Jul 26 11:41:20 2012 -0300

    Avoid using Array.prototype native methods. See #gh-57

    Also fixed bugs reported by @jdalton on same issue:

     - `every` iterate in correct order (forward).
     - `map` make sure it works properly with sparse arrays.
     - `indexOf` and `lastIndexOf` make it work on sparse arrays.
     - `reduce` and `reduceRight` allow explicit initial value of `undefined`.

    Improved specs to cover more edge cases.
  • Loading branch information...
1 parent b3d3ab8 commit a23f91857bc068535257bfbb04c0022ffbb558a4 @millermedeiros committed Aug 11, 2012
View
@@ -1,26 +1,23 @@
define(function () {
/**
- * ES5 Array.every
- * @version 0.2.1 (2011/11/25)
+ * Array every
+ * @version 0.3.0 (2012/07/26)
*/
- var every = Array.prototype.every?
- function (arr, callback, thisObj) {
- return arr.every(callback, thisObj);
- } :
- function (arr, callback, thisObj) {
- var result = true,
- n = arr.length >>> 0;
- while (n--) {
- //according to spec callback should only be called for
- //existing items
- if ( n in arr && !callback.call(thisObj, arr[n], n, arr) ) {
- result = false;
- break;
- }
- }
- return result;
- };
+ function every(arr, callback, thisObj) {
+ var result = true,
+ i = -1,
+ n = arr.length >>> 0;
+ while (++i < n) {
+ //according to spec callback should only be called for
+ //existing items
+ if ( i in arr && !callback.call(thisObj, arr[i], i, arr) ) {
+ result = false;
+ break;
+ }
+ }
+ return result;
+ }
return every;
});
View
@@ -1,22 +1,18 @@
define(['./forEach'], function (forEach) {
/**
- * ES5 Array.filter
- * @version 0.3.0 (2011/11/15)
+ * Array filter
+ * @version 0.4.0 (2012/07/26)
*/
- var filter = Array.prototype.filter?
- function (arr, callback, thisObj) {
- return arr.filter(callback, thisObj);
- } :
- function (arr, callback, thisObj) {
- var results = [];
- forEach(arr, function (val, i, arr) {
- if ( callback.call(thisObj, val, i, arr) ) {
- results.push(val);
- }
- });
- return results;
- };
+ function filter(arr, callback, thisObj) {
+ var results = [];
+ forEach(arr, function (val, i, arr) {
+ if ( callback.call(thisObj, val, i, arr) ) {
+ results.push(val);
+ }
+ });
+ return results;
+ }
return filter;
View
@@ -1,22 +1,20 @@
define(function () {
/**
- * ES5 Array.forEach
- * @version 0.3.1 (2011/11/25)
+ * Array forEach
+ * @version 0.4.0 (2012/07/26)
*/
- var forEach = Array.prototype.forEach?
- function (arr, callback, thisObj) {
- arr.forEach(callback, thisObj);
- } :
- function (arr, callback, thisObj) {
- for (var i = 0, n = arr.length >>> 0; i < n; i++) {
- //according to spec callback should only be called for
- //existing items
- if (i in arr) {
- callback.call(thisObj, arr[i], i, arr);
- }
- }
- };
+ function forEach(arr, callback, thisObj) {
+ var i = -1,
+ n = arr.length >>> 0;
+ while (++i < n) {
+ //according to spec callback should only be called for
+ //existing items
+ if (i in arr) {
+ callback.call(thisObj, arr[i], i, arr);
+ }
+ }
+ }
return forEach;
View
@@ -1,24 +1,22 @@
define(function () {
/**
- * ES5 Array.indexOf
- * @version 0.2.1 (2011/11/25)
+ * Array.indexOf
+ * @version 0.3.0 (2012/07/26)
*/
- var indexOf = Array.prototype.indexOf?
- function (arr, item, fromIndex) {
- return arr.indexOf(item, fromIndex);
- } :
- function (arr, item, fromIndex) {
- fromIndex = fromIndex || 0;
- var n = arr.length >>> 0,
- i = fromIndex < 0? n + fromIndex : fromIndex;
- for (; i < n; i++) {
- if (arr[i] === item) {
- return i;
- }
- }
- return -1;
- };
+ function indexOf(arr, item, fromIndex) {
+ fromIndex = fromIndex || 0;
+ var n = arr.length >>> 0,
+ i = fromIndex < 0? n + fromIndex : fromIndex;
+ while (i < n) {
+ //it should skip sparse items
+ if (i in arr && arr[i] === item) {
+ return i;
+ }
+ i += 1;
+ }
+ return -1;
+ }
return indexOf;
});
View
@@ -1,25 +1,22 @@
define(function () {
/**
- * ES5 Array.lastIndexOf
- * @version 0.2.1 (2011/11/25)
+ * Array lastIndexOf
+ * @version 0.3.0 (2012/07/26)
*/
- var lastIndexOf = Array.prototype.lastIndexOf?
- function (arr, item, fromIndex) {
- return fromIndex == null? arr.lastIndexOf(item) : arr.lastIndexOf(item, fromIndex);
- } :
- function (arr, item, fromIndex) {
- var len = arr.length >>> 0;
- fromIndex = (fromIndex == null || fromIndex >= len)? len - 1 : fromIndex;
- fromIndex = (fromIndex < 0)? len + fromIndex : fromIndex;
- while (fromIndex >= 0) {
- if (arr[fromIndex] === item) {
- return fromIndex;
- }
- fromIndex--;
- }
- return -1;
- };
+ function lastIndexOf(arr, item, fromIndex) {
+ var len = arr.length >>> 0;
+ fromIndex = (fromIndex == null || fromIndex >= len)? len - 1 : fromIndex;
+ fromIndex = (fromIndex < 0)? len + fromIndex : fromIndex;
+ while (fromIndex >= 0) {
+ // it should skip sparse items
+ if (fromIndex in arr && arr[fromIndex] === item) {
+ return fromIndex;
+ }
+ fromIndex--;
+ }
+ return -1;
+ }
return lastIndexOf;
});
View
@@ -1,20 +1,17 @@
define(['./forEach'], function (forEach) {
/**
- * ES5 Array.map
- * @version 0.2.0 (2011/11/15)
+ * Array map
+ * @version 0.3.0 (2012/07/26)
*/
- var map = Array.prototype.map?
- function (arr, callback, thisObj) {
- return arr.map(callback, thisObj);
- } :
- function (arr, callback, thisObj) {
- var results = [];
- forEach(arr, function (val, i, arr) {
- results[results.length] = callback.call(thisObj, val, i, arr);
- });
- return results;
- };
+ function map(arr, callback, thisObj) {
+ // need to copy arr.length because of sparse arrays
+ var results = new Array(arr.length);
+ forEach(arr, function (val, i, arr) {
+ results[i] = callback.call(thisObj, val, i, arr);
+ });
+ return results;
+ }
return map;
});
View
@@ -1,32 +1,29 @@
define(['./forEach'], function (forEach) {
/**
- * ES5 Array.reduce
- * @version 0.2.0 (2011/11/15)
+ * Array reduce
+ * @version 0.3.0 (2012/07/26)
*/
- var reduce = Array.prototype.reduce?
- function (arr, fn, initVal) {
- return initVal == null? arr.reduce(fn) : arr.reduce(fn, initVal);
- } :
- function (arr, fn, initVal) {
- var hasInit = typeof initVal !== 'undefined',
- result = initVal;
+ function reduce(arr, fn, initVal) {
+ // check for args.length since initVal might be "undefined" see #gh-57
+ var hasInit = arguments.length > 2,
+ result = initVal;
- if (!arr.length && !hasInit) {
- throw new Error('reduce of empty array with no initial value');
- }
+ if (!arr.length && !hasInit) {
+ throw new Error('reduce of empty array with no initial value');
+ }
- forEach(arr, function (val, i, arr) {
- if (! hasInit) {
- result = val;
- hasInit = true;
- } else {
- result = fn(result, val, i, arr);
- }
- });
+ forEach(arr, function (val, i, arr) {
+ if (! hasInit) {
+ result = val;
+ hasInit = true;
+ } else {
+ result = fn(result, val, i, arr);
+ }
+ });
- return result;
- };
+ return result;
+ }
return reduce;
});
View
@@ -1,36 +1,34 @@
define(function () {
/**
- * ES5 Array.reduceRight
- * @version 0.2.1 (2011/11/25)
+ * Array reduceRight
+ * @version 0.3.0 (2012/07/26)
*/
- var reduceRight = Array.prototype.reduceRight?
- function (arr, fn, initVal) {
- return initVal == null? arr.reduceRight(fn) : arr.reduceRight(fn, initVal);
- } :
- function (arr, fn, initVal) {
- var hasInit = typeof initVal !== 'undefined',
- result = initVal,
- i = arr.length >>> 0,
- val;
+ function reduceRight(arr, fn, initVal) {
+ // check for args.length since initVal might be "undefined" see #gh-57
+ var hasInit = arguments.length > 2,
+ result = initVal,
+ i = arr.length >>> 0,
+ val;
- if (!i && !hasInit) {
- throw new Error('reduce of empty array with no initial value');
- }
+ if (!i && !hasInit) {
+ throw new Error('reduce of empty array with no initial value');
+ }
- while (--i >= 0) {
- val = arr[i];
- if (typeof val !== 'undefined') {
- if (! hasInit) {
- result = val;
- hasInit = true;
- } else {
- result = fn(result, val, i, arr);
- }
- }
- }
- return result;
- };
+ while (--i >= 0) {
+ // skip sparse items but keep "undefined" items
+ if (i in arr) {
+ val = arr[i];
+ if (! hasInit) {
+ result = val;
+ hasInit = true;
+ } else {
+ result = fn(result, val, i, arr);
+ }
+ }
+ }
+ return result;
+ }
return reduceRight;
});
View
@@ -1,28 +1,23 @@
define(function (forEach) {
/**
- * ES5 Array.some
- * @version 0.2.2 (2012/06/07)
+ * Array some
+ * @version 0.3.0 (2012/07/26)
*/
- var some = Array.prototype.some?
- function (arr, callback, thisObj) {
- return arr.some(callback, thisObj);
- } :
- function (arr, callback, thisObj) {
- var result = false,
- n = arr.length,
- i = 0;
- while (i < n) {
- //according to spec callback should only be called for
- //existing items
- if ( i in arr && callback.call(thisObj, arr[i], i, arr) ) {
- result = true;
- break;
- }
- i += 1;
- }
- return result;
- };
+ function some(arr, callback, thisObj) {
+ var result = false,
+ i = -1,
+ n = arr.length >>> 0;
+ while (++i < n) {
+ //according to spec callback should only be called for
+ //existing items
+ if ( i in arr && callback.call(thisObj, arr[i], i, arr) ) {
@jdalton

jdalton Aug 11, 2012

if you ditch sparse array support you can ditch the i in arr &&.
Also it's really cool I got summoned here by the mention in the commit message :D

@millermedeiros

millermedeiros Aug 11, 2012

Owner

I created a new issue for it (#64) will definitely do it later. Don't want things to have different behavior on IE 7-8, want to avoid headaches even tho sparse arrays aren't that common (another reason to drop support).

+ result = true;
+ break;
+ }
+ }
+ return result;
+ }
return some;
});
Oops, something went wrong.

0 comments on commit a23f918

Please sign in to comment.