var array1 = [1, 4, 9, 16];
map1=array1.map(Function.call,Number);为什么map1的输出是0,1,2,3,这个映射函数在做什么?
发布于 2018-05-23 10:47:09
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)即使这样,也应该注意到,原始值正在被无用地丢弃。这样的代码样本只有在探索特定语言的行为的学术意义上才有用,或者当您想要故意混淆您的朋友作为编码挑战的一部分时。
发布于 2018-05-23 10:44:40
阅读Array#map here的用法
输入参数为map(callback, this)
在您的示例中,您提供了函数Function.call作为映射器,它是Function的构造函数。函数是说“运行这个函数”的基本方式,您绑定的this是给它提供第一个参数。
有趣的是,你给它的回调参数是args (currentValue, index)。通过传递Function.call并绑定它,您实际上是在强迫它丢弃第一个参数。这是一种让"Number“函数在索引上运行的巧妙方法(读起来很难理解)。
例如,尝试[1, 4, 9, 16].map(Function.call, String),您将看到相同的东西,但被解析为字符串["1", "4", "9", "16"]。
让我们逐步了解一下在第一次迭代中发生了什么,以获得更清晰的信息:
调用
Function.call,传递args 1 (当前值)和0 (当前索引)Number,因此就像调用Function.call的Function.call.bind(Number)(1, 0)现在,我认为大多数人都会简单地使用带有可以忽略的第一个参数的箭头函数,例如array1.map((_, i) => Number(i)) (或者更好的是,Number.parseInt,如果你试图获得一个整数)。
虽然作为软件开发人员阅读这整篇文章很酷,但我不建议在实践中使用这种map(Function.call)模式!如果您在自己的代码中遇到过它,至少要添加一个注释,这样下一个开发人员就不需要这么做了:)
发布于 2018-05-23 11:04:44
一些背景知识
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来决定调用什么函数:如果你重新绑定this,就会调用一个不同的函数。您可以使用以下命令重新绑定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]的方法。它只是索引,不必要地转换为数字,有很多间接的函数。
https://stackoverflow.com/questions/50478967
复制相似问题