【发布时间】:2018-11-01 21:19:00
【问题描述】:
var array1 = [1, 4, 9, 16];
map1=array1.map(Function.call,Number);
为什么map1的输出是[0,1,2,3],这个map函数是干什么的?
【问题讨论】:
标签: javascript
var array1 = [1, 4, 9, 16];
map1=array1.map(Function.call,Number);
为什么map1的输出是[0,1,2,3],这个map函数是干什么的?
【问题讨论】:
标签: javascript
阅读Array#map here的用法
输入参数为map(callback, this)
在您的示例中,您提供函数Function.call 作为映射器,它是Function 的构造函数。函数是说“运行这个函数”的基本方式,你绑定的this是给它第一个arg。
有趣的是,你给它的回调需要 args (currentValue, index)。通过传递 Function.call 并绑定它,您实际上是在强制它删除第一个参数。这是让您的“数字”函数在索引上运行的一种巧妙(阅读:难以理解)的方法。
例如试试[1, 4, 9, 16].map(Function.call, String),你会看到同样的东西,但被解析为字符串["1", "4", "9", "16"]。
让我们逐步了解第一次迭代中发生的情况,以便更清楚地了解:
Function.call,传递参数1(当前值)和0(当前索引)Number,所以它就像调用Function.call.bind(Number)(1, 0)
Function.call 的第一个参数表示“绑定到此上下文”,但上面的显式 bind 调用会覆盖此Number(0),当然是0,索引。现在,我认为大多数人会简单地使用带有第一个参数的箭头函数,他们可以忽略,例如array1.map((_, i) => Number(i))(或者更好的是,Number.parseInt,如果你想得到一个整数)。
虽然作为软件开发人员阅读整篇文章非常酷,但我不会在实践中推荐这种map(Function.call) 模式!如果你在自己的代码中遇到过,至少添加一个注释,这样下一个开发人员就不需要来 SO :)
【讨论】:
Array.prototype.map 调用为数组的每个成员提供的函数,并返回其返回值的新数组。
在这种情况下,提供的函数是Function.call。
Array.prototype.map 的第二个参数指定了所提供函数应该运行的上下文。
在这种情况下,上下文是Number。
Array.prototype.map 的幼稚实现可能看起来类似于:
function map(callback, thisArg) {
const ret = []
for (let index = 0; index < this.length; index++) {
const value = this[index]
ret.push(callback.call(thisArg, value, index, this))
}
return ret
}
现在,这种特殊情况使用了很多间接方式,因此很难理解为什么传递 Function.call 和 Number 应该返回 [0, 1, 2, 3],所以让我们来看看这部分。
当在thisArg (Number) 的上下文中调用callback (Function.call) 时,代码将执行以下内容:
(Function.call).call((Number), (1), (0), ([1, 4, 9, 16]))
// ^-- callback ^-- value ^-- array
// ^-- thisArg ^-- index
评估Function.call.call(...) 有点让人费解,但它相当于在第一个参数的上下文中调用call 函数,它应该是一个函数。在我们的例子中,它是。这是Number 函数。
然后我们可以将这个语句简化为:
Number.call(1, 0, [1, 4, 9, 16])
Number 函数将第一个参数转换为数字。忽略其他参数以及函数上下文。这意味着整个表达式可以简化为:
Number(0)
其中0 是index。
这就是返回值为[0, 1, 2, 3] 的原因,因为这些是来自原始数组的索引。
不用说,原始代码示例不应该在日常编程中使用。整个系统会更易于使用:
[1, 4, 9, 16].map((value, index) => index)
即使这样,也应该注意原始值被无用地丢弃了。此类代码示例仅在探索特定语言行为的学术意义上有用,或者当您想故意混淆您的朋友作为编码挑战的一部分时。
【讨论】:
Array.map 函数创建一个新数组,结果是在数组中调用 Array.map 的每个元素上调用提供的函数 (Function.call)。
例如
// Store an initial Array of String values
var stringArray = ['Matt','Long','JavaScript'];
// Invoke Function for each value of Array
mapResult = stringArray.map((currentValue) => {
// Concatenate and return
return currentValue + ' Software';
});
// Log map result
console.log(mapResult);
在对数组中的每个值执行回调时,您将传入 Number 作为要使用的“this”值。在结果数组中,每个元素都是对数组中的每个值调用给定函数的结果。
Function.call 方法调用具有给定 'this' 值和提供的参数的函数。
【讨论】:
Array.prototype.map 有两个参数:第一个是一个函数,它被数组中的每个项目调用,第二个很少使用的参数是一个this 值,第一个参数被调用。例如:
[1,2,3].map(function() { return this.x; }, {x: 3}) // returns [3,3,3]
Function.prototype.call 是所有函数上的一个函数:(Function 本身就是一个函数,所以Function.call 是Function.prototype.call),它允许使用特定的this 和特定的一组参数(单独传递,在Function.prototype.apply 的情况下不是作为数组传递)。例如:
function someFunction(y) {
return this + y;
}
someFunction.call(2, 3) // Returns 5, since this=2 and y=3
但是在实际示例中还有一个额外的细节,因为它不是在做someFunction.call,而是在做Function.call:发生了什么是Function.prototype.call 正在使用this 来确定调用了什么函数:如果你重新绑定@ 987654335@,调用了不同的函数。你可以重新绑定this,好吧...Function.prototype.call。
所以这相当于前面的例子:
function someFunction(y) {
return this + y;
}
Function.call.call(someFunction, 2, 3)
对.call 的第二次调用重新绑定第一次调用,因此它调用someFunction 而不是Function,并将参数2 和3 传递给它:它归结为someFunction.call(2, 3),我们已经已经看过了。
回到真实的例子,这样我们就可以把事情放在一起,我们有
[3,6,9].map(Function.call, Number)
第二个参数做绑定,就像.call,所以这相当于:
[3,6,9].map((...args) => Function.call.call(Number, ...args))
正如我们刚刚看到的,相当于更直接的:
[3,6,9].map((...args) => Number.call(...args))
那么,现在,...args 是什么?对于每个调用,它们是数组中的项、数组中的位置和整个数组。所以实际上这扩展为:
[
Number.call(3, 0, [3,6,9]),
Number.call(6, 1, [3,6,9]),
Number.call(9, 2, [3,6,9])
]
现在请记住,Number.call 的第一个参数是 this,而其他两个参数提供给被调用的函数 Number。据我所知,Number 不使用this,所以它基本上只是把第一个参数扔掉了,所以它是:
[
Number(0, [3,6,9]),
Number(1, [3,6,9]),
Number(2, [3,6,9])
]
Number,虽然只接受一个参数,但它会转换为一个数字。这是微不足道的,尽管因为它的论点已经是一个数字。这就是您获得[1,2,3] 的方式。它只是索引,被不必要地转换为数字,有很多函数间接。
【讨论】: