逐段拆解解析生成0-9数组的单行JavaScript代码执行逻辑
var arr = Array.apply(null, {length: 10}).map(Number.call, Number); console.log(arr); // 输出 [0,1,2,3,4,5,6,7,8,9]
代码分步拆解
整段代码可以拆为两个核心执行阶段:
阶段1:生成可遍历的长度为10的数组
对应代码:Array.apply(null, {length: 10})
Function.prototype.apply的第二个参数接受类数组对象,这里传入的{length: 10}符合类数组结构要求apply会把类数组的索引对应值(这里0~9索引默认都是undefined)作为独立参数传给Array构造函数,等价于执行Array(undefined, undefined, ..., undefined)(共10个undefined参数)- 最终返回长度为10、每个元素都是undefined的数组。注意这和直接写
Array(10)有本质区别:Array(10)生成的是只有length属性、没有实际元素的空槽数组,map会直接跳过空槽,而本阶段生成的数组包含10个实际的undefined元素,可以被map正常遍历。
阶段2:遍历生成0~9的数字序列
对应代码:.map(Number.call, Number)
首先明确Array.prototype.map的参数规则:第一个参数是遍历用的回调函数,第二个参数是回调函数执行时的this绑定值。
这部分的执行逻辑拆解:
- 传入的回调函数
Number.call本质是所有函数都继承的Function.prototype.call方法,传入的回调this绑定值为Number构造函数本身。 - map遍历每一项时,会自动给回调传入三个参数:
当前元素值、当前索引、原数组,同时把回调的this绑定为我们传入的Number。 call方法的原生执行规则是:call内部的this就是要被调用的目标函数,call的第一个参数是目标函数的this指向,后续所有参数都会传给目标函数作为入参。- 结合以上规则,每一次遍历实际执行逻辑为:
- 要调用的目标函数是
call内部的this,也就是我们绑定的Number - 传给
Number的this是map回调的第一个参数(当前元素值,这里为undefined,而Number作为普通函数调用时完全不关心this指向,所以该值无任何作用) - 传给
Number的实际入参是map回调的第二个参数(当前索引),第三个参数原数组会被Number直接忽略 - 等价于每次执行
Number(当前索引),直接返回索引本身的数字值
- 要调用的目标函数是
遍历完10个元素后,就得到了由索引值组成的0~9数字数组。
内容的提问来源于stack exchange,提问作者Satish Chandra Gupta
相关产品推荐
相关产品推荐

