Table of Contents
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
函数接受三个参数,分别是:
item
: 遍历的当前元素index
: 遍历的当前元素的索引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
发生的步骤:
图解:
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. 调用
O
的length
属性的[[GET] ]
方法,并把结果赋值给lenValue
这一步其实就是把要遍历的对象的
length
属性的值保存起来,即要遍历对象的长度,因此如果对象不存在这个属性,这一步就无法通过了。- c. 执行
len = ToUint32(lenValue)
将lenValue
转成无符号整型数据(0~232 -1) d. 检测
callbackfn
是否是 isCallable ,如果结果是:false
则会抛出TypeError
异常isCallable
操作结果(结果可知,检测的是否是函数):参数类型 结果 Undefined Return false. Null Return false. Boolean Return false. Number Return false. String Return 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. 如果
kPresent
是true
表面属性元素存在kValue = [[Get] ]O(Pk)
去O
对象中取到Pk
对应的值mappedValue = T.[[Call] ](callbackfn, kValue, k, O)
执行回调函数,得到处理后的结果保存到
mappedValue
中A
调用[[DefineOwnProperty] ]
参数:Pk
和false
这一步是在新建的副本对象上定义一个
Pk
属性,并且设置其属性描述符:{ [[Value]]: mappedValue, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }
IV.
k--
索引减1
返回h
重复执行,直到k > = len
为止最终
A
上会有所有数组经过处理后的值。
- I.
- i. 最后返回
A