admin管理员组

文章数量:1022793

Is the order of iterating through an array using one of the native methods (map, forEach, reduce, filter, etc) deterministic and guaranteed by the standard?

EG, are foo, bar, baz, and qux guaranteed to be [0, 2, 6, 12]?

const a = [1, 2, 3, 4];
const foo = a.map((item, index) => item * index);
const bar = []; a.forEach((item, index) => bar[index] = item * index);
const baz = []; a.reduce((total, item, index) => baz[index] = item * index, 0);
const qux = []; a.filter((item, index) => qux[index] = item * index);
// etc

(These are (very) contrived examples)

Is the order of iterating through an array using one of the native methods (map, forEach, reduce, filter, etc) deterministic and guaranteed by the standard?

EG, are foo, bar, baz, and qux guaranteed to be [0, 2, 6, 12]?

const a = [1, 2, 3, 4];
const foo = a.map((item, index) => item * index);
const bar = []; a.forEach((item, index) => bar[index] = item * index);
const baz = []; a.reduce((total, item, index) => baz[index] = item * index, 0);
const qux = []; a.filter((item, index) => qux[index] = item * index);
// etc

(These are (very) contrived examples)

Share Improve this question edited Feb 22, 2018 at 0:22 matisetorm 8538 silver badges21 bronze badges asked Aug 15, 2017 at 19:04 craigmichaelmartincraigmichaelmartin 6,5191 gold badge23 silver badges26 bronze badges 2
  • 3 Yes, the numeric properties are traversed in ascending order. It's explicitly described in the language spec. – Pointy Commented Aug 15, 2017 at 19:06
  • btw, you need to use a start value for reduce, like a.reduce((total, item, index) => baz[index] = item * index, null); – Nina Scholz Commented Aug 15, 2017 at 19:09
Add a ment  | 

1 Answer 1

Reset to default 5

The callback function is called for each element present in the array, in ascending order. It is not called for missing elements. (Missing elements? Yes, JavaScript handle sparse arrays)

var test = [];
test[30] = 'Test'; // sparse array, only one element defined.

test.forEach(
  function(value){
    console.log(value); // will only be called one time.
  }
);

From the standard: ECMA-262

22.1.3.10 Array.prototype.forEach ( callbackfn [ , thisArg ] )

NOTE 1

callbackfn should be a function that accepts three arguments. forEach calls callbackfn once for each element present in the array, in ascending order. callbackfn is called only for elements of the array which actually exist; it is not called for missing elements of the array

If a thisArg parameter is provided, it will be used as the this value for each invocation of callbackfn. If it is not provided, undefined is used instead.

callbackfn is called with three arguments: the value of the element, the index of the element, and the object being traversed.

forEach does not directly mutate the object on which it is called but the object may be mutated by the calls to callbackfn.

When the forEach method is called with one or two arguments, the following steps are taken:

  1. Let O be ? ToObject(this value).
  2. Let len be ? ToLength(? Get(O, "length")).
  3. If IsCallable(callbackfn) is false, throw a TypeError exception.
  4. If thisArg was supplied, let T be thisArg; else let T be undefined.
  5. Let k be 0.
  6. Repeat, while k < len a. Let Pk be ! ToString(k). b. Let kPresent be ? HasProperty(O, Pk). c. If kPresent is true, then i. Let kValue be ? Get(O, Pk). ii. Perform ? Call(callbackfn, T, « kValue, k, O »). d. Increase k by 1.
  7. Return undefined.

Is the order of iterating through an array using one of the native methods (map, forEach, reduce, filter, etc) deterministic and guaranteed by the standard?

EG, are foo, bar, baz, and qux guaranteed to be [0, 2, 6, 12]?

const a = [1, 2, 3, 4];
const foo = a.map((item, index) => item * index);
const bar = []; a.forEach((item, index) => bar[index] = item * index);
const baz = []; a.reduce((total, item, index) => baz[index] = item * index, 0);
const qux = []; a.filter((item, index) => qux[index] = item * index);
// etc

(These are (very) contrived examples)

Is the order of iterating through an array using one of the native methods (map, forEach, reduce, filter, etc) deterministic and guaranteed by the standard?

EG, are foo, bar, baz, and qux guaranteed to be [0, 2, 6, 12]?

const a = [1, 2, 3, 4];
const foo = a.map((item, index) => item * index);
const bar = []; a.forEach((item, index) => bar[index] = item * index);
const baz = []; a.reduce((total, item, index) => baz[index] = item * index, 0);
const qux = []; a.filter((item, index) => qux[index] = item * index);
// etc

(These are (very) contrived examples)

Share Improve this question edited Feb 22, 2018 at 0:22 matisetorm 8538 silver badges21 bronze badges asked Aug 15, 2017 at 19:04 craigmichaelmartincraigmichaelmartin 6,5191 gold badge23 silver badges26 bronze badges 2
  • 3 Yes, the numeric properties are traversed in ascending order. It's explicitly described in the language spec. – Pointy Commented Aug 15, 2017 at 19:06
  • btw, you need to use a start value for reduce, like a.reduce((total, item, index) => baz[index] = item * index, null); – Nina Scholz Commented Aug 15, 2017 at 19:09
Add a ment  | 

1 Answer 1

Reset to default 5

The callback function is called for each element present in the array, in ascending order. It is not called for missing elements. (Missing elements? Yes, JavaScript handle sparse arrays)

var test = [];
test[30] = 'Test'; // sparse array, only one element defined.

test.forEach(
  function(value){
    console.log(value); // will only be called one time.
  }
);

From the standard: ECMA-262

22.1.3.10 Array.prototype.forEach ( callbackfn [ , thisArg ] )

NOTE 1

callbackfn should be a function that accepts three arguments. forEach calls callbackfn once for each element present in the array, in ascending order. callbackfn is called only for elements of the array which actually exist; it is not called for missing elements of the array

If a thisArg parameter is provided, it will be used as the this value for each invocation of callbackfn. If it is not provided, undefined is used instead.

callbackfn is called with three arguments: the value of the element, the index of the element, and the object being traversed.

forEach does not directly mutate the object on which it is called but the object may be mutated by the calls to callbackfn.

When the forEach method is called with one or two arguments, the following steps are taken:

  1. Let O be ? ToObject(this value).
  2. Let len be ? ToLength(? Get(O, "length")).
  3. If IsCallable(callbackfn) is false, throw a TypeError exception.
  4. If thisArg was supplied, let T be thisArg; else let T be undefined.
  5. Let k be 0.
  6. Repeat, while k < len a. Let Pk be ! ToString(k). b. Let kPresent be ? HasProperty(O, Pk). c. If kPresent is true, then i. Let kValue be ? Get(O, Pk). ii. Perform ? Call(callbackfn, T, « kValue, k, O »). d. Increase k by 1.
  7. Return undefined.

本文标签: