使用序列号在Javascript中映射数组

时间:2016-06-17 18:51:30

标签: javascript arrays numbers map-function

以下代码:

let myArray = Array.apply(null, {length: 10}).map(Number.call, Number);

创建以下数组:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

我只是不明白为什么。我无法在互联网上找到解释此行为的任何内容。有谁知道为什么这样做的方式呢?也许是某些文档的链接?

4 个答案:

答案 0 :(得分:12)

让我们将表达式分解为两部分:

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);

换句话说,我们正在创建一个包含10个元素的数组,其值为undefined(注意它不再稀疏)

2)进入第二个表达式:

.map(Number.call, Number);

第一个参数是一个回调函数,用于应用于数组中的每个元素,第二个参数是回调中的this值。

让我们分解这个表达式。首先,我们可以将回调函数写为匿名函数:

Array.apply(null, {length: 10}).map(function() {
  return Number.call.apply(this, arguments)
}, Number)

然后我们意识到Number.callFunction.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的元素,是this调用的Number值,也就是说我们丢弃它。第二个参数是索引,它是我们关心的值,第三个参数是不需要的,因为Number只接受一个参数,所以这个也被丢弃了。

在这种情况下,Number函数用作indentity函数:

function id(x) {
  return x
}

它只是一个参数的函数,它返回该参数。这就是我们关心的一切。由于index已经是一个数字,我们得到了:

Number(index) === id(index)

希望有助于进一步理解。

修改:要扩展Array(10)无法使用mapArray.apply(null, {length: 10})等迭代方法的原因,我们必须查看{ {3}}(滚动到“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

答案 1 :(得分:5)

Shop Manager

创建一个长度为10的数组,其中所有元素都为Array.apply(null, {length: 10})

undefined

将为参数.map(Number.call, Number) 并将Number.call设置为(element, index, array)的每个元素调用this。调用的第一个参数将被视为Number(这里不相关),所有其他参数都按原样传递,第一个参数是索引。而Number现在将其第一个参数this转换为数字(这里:将返回索引,因为它是一个数字),以及那个地图将写入其返回数组。

答案 2 :(得分:0)

Array.apply(null, {length: 10}) 

//>它输出长度为10的undefined数组,原因: 它需要null来执行,因为它不需要执行,除了此参数必须是tepeof对象,而且我们知道:typeof null ==='object',如果您将放置任何其他对象而不是null,它将执行同样的事情,只关系第二个参数的长度是什么(它测试第二个参数的长度),

.map(Number.call,Number);

分解(我们知道Number构造函数是Function.prototype(Number。 proto ),所以):

.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 =>数字

call.apply(Number, arguments); => call(arguments[0], arguments[1])

原因:参数是类似数组的对象,我们仍然可以将其传递给apply方法,但是我们无法调用,因为它采用了逗号分隔的参数。您无法将参数定义为参数,因此需要指出它的含义正在寻找:索引,即参数[1],因为此值必须带任何对象,所以带:null或其他任何值,但必须存在:

return Number.call(null, arguments[1]);

这里编号是一个身份函数:

function example(x){
 return x;
}

所以Number(e)== example(e); 所以在第一次迭代中:

Number(0) //it takes 0 index:

return 0..

然后:

Number(1)//cause it takes the index of the second element:

return 1..

感谢阅读...

答案 3 :(得分:0)

es6简化版

let k = Array.from({ length: 5 }).map((currentElement, i) => i)

console.log(k)

Output -[0, 1, 2, 3, 4]