【ECMA262学习系列】 15.4.4.19 Array.prototype.map(callbackfn[, thisArg])

Table of Contents

  1. 15 标准内置对象(Standard Built-in ECMAScript Objects)
    1. 15.5 数组对象(Array)
      1. 15.4.4 数组原型对象的属性(Array.prototype)
        1. 15.4.4.19 Array.prototype.map(callbackFn[, thisArg])

15 标准内置对象(Standard Built-in ECMAScript Objects)

15.5 数组对象(Array)

15.4.4 数组原型对象的属性(Array.prototype)

15.4.4.19 Array.prototype.map(callbackFn[, thisArg])

函数功能:遍历数组的每一项,然后对每一项执行 callbackFn 将结果返回,最后把所有返回的结果组合成数组作为map 调用的最终返回值。

注意点:不会遍历空元素(null, undefined, false 等依旧会遍历)

callbackFn 函数接受三个参数,分别是:

  1. item : 遍历的当前元素
  2. index : 遍历的当前元素的索引
  3. array : 被遍历的数组本身

const nums = [1, 2, 3, 4, , 6]

const cbfn = (item, index, _nums) => {
  console.log(item, index, '_nums === nums ? ' + (_nums === nums))
  return item
}

const obj = {
  cbfn: (item, index, _nums) => {
    console.error(item, index, '_nums === nums ? ' + (_nums === nums))
    return item
  }
}

const newNums = nums.map(cbfn, obj)

结果:

1 0 '_nums === nums ? true'
2 1 '_nums === nums ? true'
3 2 '_nums === nums ? true'
4 3 '_nums === nums ? true'
6 5 '_nums === nums ? true'
newNums:  [ 1, 2, 3, 4, <1 empty item>, 6 ]
undefined

使用一个或两个参数调用 map 发生的步骤:

img

图解:

  • a. 让 O 作为调用 ToObject (this) 的结果

    ToObject 一个抽象操作,强制将它的参数转成一个对象,转换方式根据下表:

    参数类型转换结果
    Undefined抛出 `TypeError` 异常
    Null抛出 `TypeError` 异常
    Boolean创建一个 `Boolean` 对象,对象内部的原始值会被设置成参数值
    Number创建一个 `Number` 对象,对象内部的原始值会被设置成参数值
    String创建一个 `String` 对象,对象内部的原始值会被设置成参数值
    Object结果就是参数自身

    对于 Boolean, String, Number 会转成对应的对象,之后对象中的 [[PrimitiveValue] ] 的值就是参数的值,这个值我们可以通过 v.valueOf() 得到。

    比如:

    const b = new Boolean(false)
    console.log(b.valueOf()) // false
    const n = new Number(3)
    console.log(n.valueOf()) // 3
    const s = new String('hello')
    console.log(s.valueOf()) // 'hello'
    
    // 看下数组 ToObject 示例
    
    const arr = [1, 2, , 3]
    ;console.log(
      'empty element: arr.hasOwnProperty("2") === true ? ' + arr.hasOwnProperty('2'),
    )
    console.log('empty element: arr[2] == ' + arr[2])
    

    RESULTS:

    false
    3
    hello
    empty element: arr.hasOwnProperty("2") === true ? false
    empty element: arr[2] == undefined
    undefined
    

    从结果可以发现,数组对于空元素对象化的时候是不会将其属性化,因此通过
    hasOwnProperty("2") 得出的结果是 false 但是依旧可以通过 arr[2] 去访问,
    只不过值是 undefined ,记住这个很重要,因为后面的过程分析中会用到这点。

  • b. 调用 Olength 属性的 [[GET] ] 方法,并把结果赋值给 lenValue

    这一步其实就是把要遍历的对象的 length 属性的值保存起来,即要遍历对象的长度,因此如果对象不存在这个属性,这一步就无法通过了。

  • c. 执行 len = ToUint32(lenValue)lenValue 转成无符号整型数据(0~232 -1)
  • d. 检测 callbackfn 是否是 isCallable ,如果结果是: false 则会抛出 TypeError 异常

    isCallable 操作结果(结果可知,检测的是否是函数):

    参数类型结果
    UndefinedReturn false.
    NullReturn false.
    BooleanReturn false.
    NumberReturn false.
    StringReturn false.
    Object如果参数对象有 `[[Call] ]` 内部函数返回 `true` ,否则返回 `false`
      
  • e. 检测第二个参数 thisArg ,如果有则 T = thisArg; 否则 T = undefined;

    即初始化第二个参数的值。

  • f. A = new Array(len) 创建一个长度为 len (步骤 c 中的 len )的数组副本,用来存储处理后的结果。
  • g. k = 0 创建遍历索引
  • h. 当 k < len 时候重复下面的步骤

    • I. Pk = ToString(k) 将索引值转成字符串
    • II. kPresent = O([[HasProperty] ])(Pk) 对象 O 去调用内部方法 [[HasPropery] ] 参数是 Pk
      即在目标数组转成对象之后,然后去里面找“当前索引值转成字符串之后的属性”,结果
      kPresent = true/false
    • III. 如果 kPresenttrue 表面属性元素存在

      • kValue = [[Get] ]O(Pk)O 对象中取到 Pk 对应的值
      • mappedValue = T.[[Call] ](callbackfn, kValue, k, O)

        执行回调函数,得到处理后的结果保存到 mappedValue

      • A 调用 [[DefineOwnProperty] ] 参数: Pkfalse

        这一步是在新建的副本对象上定义一个 Pk 属性,并且设置其属性描述符:

        {
            [[Value]]: mappedValue,
            [[Writable]]: true,
            [[Enumerable]]: true,
            [[Configurable]]: true
        }
        
    • IV. k-- 索引减 1 返回 h 重复执行,直到 k > = len 为止

      最终 A 上会有所有数组经过处理后的值。

  • i. 最后返回 A
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

若叶岂知秋vip

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值