.map() 等高阶函数如何在 JavaScript 内部工作?

How do higher-order functions, like .map(), work internally in JavaScript?

现在每个人都尝试使用这种 higher-order functions 来获得有希望的结果,同时编写更少的代码。但是我想知道这些函数在内部是如何工作的。

假设我写这样的东西

var numbers = [16, 25, 36];
var results = numbers.map(Math.sqrt);
console.log(results); // [4, 5, 6]

我知道 'number' 数组的每个元素都在逐个迭代,但是 how?

我试图搜索它,但我还没有得到满意的答案。

.map 只是一个接受回调的方法,为数组的每个项目调用回调,并将值分配给新数组。没什么特别的。您甚至可以很容易地自己实现它:

Array.prototype.myMap = function(callback) {
  const newArr = [];
  for (let i = 0; i < this.length; i++) {
    newArr.push(callback(this[i], i, this));
  }
  return newArr;
}

var numbers = [16, 25, 36];
var results = numbers.myMap(Math.sqrt);
console.log(results); // [4, 5, 6]

为了完全符合规范,您需要 also need 检查 this 是一个对象,callback 是可调用的,以及.call 带有第二个参数的回调传递给 myMap 如果有的话,但这些细节对于开始理解高阶函数并不重要。

我想每个供应商都应该按照 spec

实施它

实际实现,例如 V8 可能有点复杂,请参考 this answer 开始。您也可以参考github中的v8源码,但孤立地只看一部分可能不太容易。

引用上面的回答:

V8 developer here. We have several different implementation techniques for "builtins": some are written in C++, some in Torque, some in what we call CodeStubAssembler, and a few directly in assembly. In earlier versions of V8, some were implemented in JavaScript. Each of these strategies has its own strengths (trading off code complexity, debuggability, performance in various situations, binary size, and memory consumption); plus there is always the historical reason that code has evolved over time.

ES2015 规范:

  1. O为ToObject(this value).
  2. ReturnIfAbrupt(O).
  3. len 为 ToLength(Get(O, "length")).
  4. ReturnIfAbrupt(len).
  5. 如果 IsCallable(callbackfn) 为 false,抛出一个 TypeError 异常。
  6. 如果提供了 thisArg,则让 TthisArg;否则让 Tundefined.
  7. A为ArraySpeciesCreate(O, len).
  8. ReturnIfAbrupt(A).
  9. k为0。
  10. 重复,同时 k < len
    1. Pk 为 ToString(k).
    2. kPresent为HasProperty(O,Pk).
    3. ReturnIfAbrupt(kPresent).
    4. 如果 kPresenttrue,则
      1. kValue为Get(O,Pk).
      2. ReturnIfAbrupt(kValue).
      3. mappedValue 为 Call(callbackfn, T, « kValue, k, O»).
      4. ReturnIfAbrupt(mappedValue).
      5. status为CreateDataPropertyOrThrow (A, Pk, mappedValue ).
      6. ReturnIfAbrupt(状态).
    5. k 增加 1。
  11. ReturnA.