ES6标准入门(第 3 版)
25.4 数组的 map 方法
阅读(

ECMAScript 6 简介

let 和 const 命令

变量的解构赋值

字符串的扩展

正则的扩展

数值的扩展

函数的扩展

数组的扩展

对象的扩展

Symbol

Set 和 Map 数据结构

Proxy

Reflect对象

Promise对象

Iterator 和 for...of 循环

Generator函数语法

Generator函数的异步应用

async函数

Class的基本语法

Class的继承

Decorator

ES6模块

加载ES6模块

ES6编码规范

读懂ES6规格

概述

相等运算符

数组的空位

数组的 map 方法

规格的22.1.3.15 小节定义了数组的map方法。该小节先是总体描述map方法的行为,里面没有提到数组空位。

后面的算法描述是这样的。

  1. LetObeToObject(this value).
  2. ReturnIfAbrupt(O).
  3. LetlenbeToLength(Get(O, "length")).
  4. ReturnIfAbrupt(len).
  5. IfIsCallable(callbackfn)isfalse, throw a TypeError exception.
  6. IfthisArgwas supplied, letTbethisArg; else letTbeundefined.
  7. LetAbeArraySpeciesCreate(O, len).
  8. ReturnIfAbrupt(A).
  9. Letkbe 0.
  10. Repeat, whilek<len\ a. LetPkbeToString(k).\ b. LetkPresentbeHasProperty(O, Pk).\ c.ReturnIfAbrupt(kPresent).\ d. IfkPresentistrue, then\ d-1. LetkValuebeGet(O, Pk).\ d-2.ReturnIfAbrupt(kValue).\ d-3. LetmappedValuebeCall(callbackfn, T, «kValue, k, O»).\ d-4.ReturnIfAbrupt(mappedValue).\ d-5. LetstatusbeCreateDataPropertyOrThrow (A, Pk, mappedValue).\ d-6.ReturnIfAbrupt(status).\ e. Increasekby 1.
  11. ReturnA.

翻译如下。

  1. 得到当前数组的this对象
  2. 如果报错就返回
  3. 求出当前数组的length属性
  4. 如果报错就返回
  5. 如果 map 方法的参数callbackfn不可执行,就报错
  6. 如果 map 方法的参数之中,指定了this,就让T等于该参数,否则Tundefined
  7. 生成一个新的数组A,跟当前数组的length属性保持一致
  8. 如果报错就返回
  9. 设定k等于 0
  10. 只要k小于当前数组的length属性,就重复下面步骤\ a. 设定Pk等于ToString(k),即将K转为字符串\ b. 设定kPresent等于HasProperty(O, Pk),即求当前数组有没有指定属性\ c. 如果报错就返回\ d. 如果kPresent等于true,则进行下面步骤\ d-1. 设定kValue等于Get(O, Pk),取出当前数组的指定属性\ d-2. 如果报错就返回\ d-3. 设定mappedValue等于Call(callbackfn, T, «kValue, k, O»),即执行回调函数\ d-4. 如果报错就返回\ d-5. 设定status等于CreateDataPropertyOrThrow (A, Pk, mappedValue),即将回调函数的值放入A数组的指定位置\ d-6. 如果报错就返回\ e.k增加 1
  11. 返回A

仔细查看上面的算法,可以发现,当处理一个全是空位的数组时,前面步骤都没有问题。进入第 10 步的 b 时,kpresent会报错,因为空位对应的属性名,对于数组来说是不存在的,因此就会返回,不会进行后面的步骤。

const arr = [, , ,];
arr.map(n => {
  console.log(n);
  return 1;
}) // [, , ,]

上面代码中,arr是一个全是空位的数组,map方法遍历成员时,发现是空位,就直接跳过,不会进入回调函数。因此,回调函数里面的console.log语句根本不会执行,整个map方法返回一个全是空位的新数组。

V8 引擎对map方法的实现如下,可以看到跟规格的算法描述完全一致。

function ArrayMap(f, receiver) {
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map");

  // Pull out the length so that modifications to the length in the
  // loop will not affect the looping and side effects are visible.
  var array = TO_OBJECT(this);
  var length = TO_LENGTH_OR_UINT32(array.length);
  return InnerArrayMap(f, receiver, array, length);
}

function InnerArrayMap(f, receiver, array, length) {
  if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);

  var accumulator = new InternalArray(length);
  var is_array = IS_ARRAY(array);
  var stepping = DEBUG_IS_STEPPING(f);
  for (var i = 0; i < length; i++) {
    if (HAS_INDEX(array, i, is_array)) {
      var element = array[i];
      // Prepare break slots for debugger step in.
      if (stepping) %DebugPrepareStepInIfStepping(f);
      accumulator[i] = %_Call(f, receiver, element, i, array);
    }
  }
  var result = new GlobalArray();
  %MoveArrayContents(accumulator, result);
  return result;
}

如果本教程对您帮助很大,请随意打赏。您的支持,将鼓励我们提供更好的教程!

← 键盘方向键翻页 →
返回顶部 手机访问 关注微信 返回底部

扫码访问歪脖网

随时随地,想看就看

关注歪脖网微信

分享 web 知识、交流 web 经验