以下代码:
let myArray = Array.apply(null, {length: 10}).map(Number.call, Number);
创建以下数组:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
我只是不明白为什么。我在互联网上找不到任何解释这种行为的东西。有人知道为什么这样做的方式有效吗?也许是指某些文档的链接?
让我们以两个部分分解表达式:
1)让我们讨论第一个表达式:
Array.apply(null, {length: 10})
在JavaScript中,Array
构造函数可以采用一个参数来创建一定长度的数组,例如:
Array(10) // makes an array of length 10
此数组是一个稀疏的数组(一个包含没有元素的索引的数组)。您可以想象我们生成了以下数组:
[,,,,,,,,] // Array with 10 indexes, but no elements
您可以将JavaScript中的数组视为具有length
属性和编号索引的对象。例如,以下是数组的有效表示:
var arr = {length: 3, 0: 1, 1: 2, 2: 3} // this represents the array [1, 2, 3]
在JavaScript中,我们称此对象为"类似数组的对象"。您可以使用常规的for
循环迭代此对象:
for (var i=0; i<arr.length; i++) {
console.log(arr[i]) // logs 1 .. 2 .. 3
}
但是此对象不是Array
构造函数的实例:
arr instanceof Array // false
幸运的是,任何类似数组的对象都可以转换为数组:
Array.prototype.slice.call({length: 3, 0: 1, 1: 2, 2: 3}) // [1, 2, 3]
所有数组方法都是有意通用的,可以允许此行为,因此您可以使用forEach
轻松循环:
Array.prototype.forEach.call({length: 3, 0: 1, 1: 2, 2: 3}, function(x) {
console.log(x)
})
现在,回到第一个表达式:
Array.apply(null, {length: 10})
分解上述表达式了解类似数组的对象,我们可以看到这等同于:
Array(undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
换句话说,我们正在创建一个具有undefined
值的10个元素的数组(请注意,它不再稀疏)
2)进入第二个表达式:
.map(Number.call, Number);
第一个参数是一个回调函数,用于应用于数组中的每个元素,第二个参数是回调内的this
值。
让我们分解此表达。首先,我们可以将回调函数写为匿名函数:
Array.apply(null, {length: 10}).map(function() {
return Number.call.apply(this, arguments)
}, Number)
然后我们意识到Number.call
是Function.prototype.call
的速记:
Array.apply(null, {length: 10}).map(function() {
return Function.prototype.call.apply(this, arguments)
}, Number)
接下来,我们在 this
值中排列:
Array.apply(null, {length: 10}).map(function() {
return Function.prototype.call.apply(Number, arguments)
})
最后,我们分解了该函数的应用:
Array.apply(null, {length: 10}).map(function() {
return Number.call(arguments[0], arguments[1], arguments[2]) // map provides 3 arguments
})
您可以看到,第一个参数是元素,即 undefined
是呼叫 Number
的 this
值,也就是说我们丢弃了它。第二个论点是索引,这是我们关心的价值,不需要第三个参数,因为Number
也只采用一个参数,因此也被丢弃。
在这种情况下,Number
函数用作身份函数:
function id(x) {
return x
}
它只是一个函数,它返回传递到其中的参数的函数。这就是我们所关心的。因为index
已经是一个数字,所以我们得到:
Number(index) === id(index)
希望有助于进一步理解。
编辑:扩展了Array(10)
不使用迭代方法(例如map
与Array.apply(null, {length: 10})
)的原因,我们必须查看MAP的实现(滚动到" polyfill"标题)。
原因是因为正如我之前指出的那样, Array(10)
是一个稀疏的数组,它没有任何值,只有一个长度。通过查看实现,我们可以看到正在发生的事情:
// 8. Repeat, while k < len
while (k < len) {
var kValue, mappedValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal
// method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal
// method of O with argument Pk.
kValue = O[k];
您可以看到k in O
in
运算符首先检查存在的检查,并且该值不存在;它不是undefined
,而是不存在。这与仅像O[k]
这样的属性访问的情况不同,如果该属性不存在,它将为您提供undefined
的值。
var o = {}
'p' in o // false
o.p // undefined
Array.apply(null, {length: 10})
创建一个长度为10的数组,所有元素均为undefined
。
.map(Number.call, Number)
将使用参数(element, index, array)
调用每个元素的Number.call
,并将this
设置为Number
。第一个呼叫的论点将作为this
(在此不相关),并且所有其他参数均被视为索引。现在,数字将将其第一个参数index
转换为一个数字(此处:将返回索引,因为它是一个数字),这就是地图将写入其返回数组。
ES6 Simpliedfied版本
let k = Array.from({ length: 5 }).map((currentElement, i) => i)
console.log(k)
// Output -[0, 1, 2, 3, 4]
Array.apply(null, {length: 10})
//&gt;它输出了未定义的阵列,长度为十个原因,为什么:它需要执行为null,因为它不需要执行,除了此参数必须是tepeof对象,并且众所周知:typeof null ==='对象',如果您将任何其他对象而不是null放置,它将执行同一件事,仅重要的是第二个参数的长度(它测试第二个参数的长度),
.map(number.call,number);
分解(我们知道数字构造函数是函数。
.map(function(){
Function.prototype.call.apply(this, arguments)
}, Number)// the second arg is the this value that map function takes during each iteration
我们还知道这是数字,因为它每次调用号码都这样:
Function.prototype.call.apply(Number, arguments)
});//在这里我们不需要第二个参数
现在我们再次撰写了所有内容:function.prototype =&gt;编号,
call.apply(Number, arguments); => call(arguments[0], arguments[1])
原因:参数是类似数组的对象,我们仍然可以将其传递给应用方法,但是我们不能打电话,因为它以逗号分隔的参数。您不能将参数定义为参数,因此您需要指示它正在寻找:索引,这就是参数[1],因为此值必须采用任何对象,因此请使用:null或任何东西,但必须存在:
return Number.call(null, arguments[1]);
这里的数字是一个身份函数:
function example(x){
return x;
}
因此数字(e)==示例(e);因此,在第一次迭代中:
Number(0) //it takes 0 index:
return 0..
然后:
Number(1)//cause it takes the index of the second element:
return 1..
感谢您的阅读...