在 javascript 的高阶函数中使用原型函数
Using prototype functions in higher order functions in javascript
我正在尝试使用 reduce 连接一个数组数组,我想我可以像这样使用 Array.prototype.concat 函数:
arr = [[1],[2],[3]]
arr.reduce((a, b) => Array.prototype.concat(a, b), [])
它工作正常并给我数组 [1, 2, 3]
。然后我想我可以更聪明地这样做:
arr = [[1],[2],[3]]
arr.reduce(Array.prototype.concat, [])
然而,这给了我一个错误:
TypeError: Array.prototype.concat called on null or undefined
at Array.reduce (native)
at Object.<anonymous> (/home/axel/Developer/temp/reduce2.js:2:5)
at Module._compile (module.js:556:32)
at Object.Module._extensions..js (module.js:565:10)
at Module.load (module.js:473:32)
at tryModuleLoad (module.js:432:12)
at Function.Module._load (module.js:424:3)
at Module.runMain (module.js:590:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
好像认为Array.prototype.concat
是undefined
。这是为什么?
Array.prototype.concat
期望上下文 (this
) 是一个数组,在您的第一个示例中,上下文实际上是 Array.prototype
,它看起来很像一个数组,因此它可以工作。
然而,您的第二个示例通过引用传递 concat 函数,因此上下文为 null 或未定义。
更正确的方法是使用 Function.prototype.call
将上下文绑定到数组之一或直接在数组上调用方法,例如
arr = [[1],[2],[3]];
arr.reduce((a, b) => Array.prototype.concat.call(a, b), []);
// Or
arr.reduce((a, b) => a.concat(b), []);
concat
作为某个对象的方法运行(即,方法执行的 this
值)。将函数传递给函数时,不会传递任何 this
值。因此,您实际上是在做类似以下的事情:
var rawConcat = Array.prototype.concat;
rawConcat(a,b);
您可以使用 bind
创建一个函数的副本,其中刻录了特定的 this
:
arr.reduce(Array.prototype.concat.bind(Array.prototype), [])
但是,既然已经解决了,还有其他几个问题会阻止您这样做。
首先,reduce
实际上得到 四个 个参数,包括当前索引和整个数组。您可以通过让 (a,b)=>
lambda 仅将这四个参数中的两个传递给 concat
来忽略这些。这很好,但是当您直接将函数作为参数提供给 reduce
时,它将使用所有四个参数,因此您将获得调用的结果 Array.prototype.concat(a, b, currentIndex, arr)
.
此外,您所做的并不是 Array.prototype
的合理使用。 concat
函数连接其参数并将它们附加到 this
值的副本。由于 Array.prototype
本身只是一个空数组(尽管有许多其他数组用作继承属性的自有属性),这实际上与 [].concat(a,b)
或(可能更易读)a.concat(b)
.
我正在尝试使用 reduce 连接一个数组数组,我想我可以像这样使用 Array.prototype.concat 函数:
arr = [[1],[2],[3]]
arr.reduce((a, b) => Array.prototype.concat(a, b), [])
它工作正常并给我数组 [1, 2, 3]
。然后我想我可以更聪明地这样做:
arr = [[1],[2],[3]]
arr.reduce(Array.prototype.concat, [])
然而,这给了我一个错误:
TypeError: Array.prototype.concat called on null or undefined
at Array.reduce (native)
at Object.<anonymous> (/home/axel/Developer/temp/reduce2.js:2:5)
at Module._compile (module.js:556:32)
at Object.Module._extensions..js (module.js:565:10)
at Module.load (module.js:473:32)
at tryModuleLoad (module.js:432:12)
at Function.Module._load (module.js:424:3)
at Module.runMain (module.js:590:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
好像认为Array.prototype.concat
是undefined
。这是为什么?
Array.prototype.concat
期望上下文 (this
) 是一个数组,在您的第一个示例中,上下文实际上是 Array.prototype
,它看起来很像一个数组,因此它可以工作。
然而,您的第二个示例通过引用传递 concat 函数,因此上下文为 null 或未定义。
更正确的方法是使用 Function.prototype.call
将上下文绑定到数组之一或直接在数组上调用方法,例如
arr = [[1],[2],[3]];
arr.reduce((a, b) => Array.prototype.concat.call(a, b), []);
// Or
arr.reduce((a, b) => a.concat(b), []);
concat
作为某个对象的方法运行(即,方法执行的 this
值)。将函数传递给函数时,不会传递任何 this
值。因此,您实际上是在做类似以下的事情:
var rawConcat = Array.prototype.concat;
rawConcat(a,b);
您可以使用 bind
创建一个函数的副本,其中刻录了特定的 this
:
arr.reduce(Array.prototype.concat.bind(Array.prototype), [])
但是,既然已经解决了,还有其他几个问题会阻止您这样做。
首先,reduce
实际上得到 四个 个参数,包括当前索引和整个数组。您可以通过让 (a,b)=>
lambda 仅将这四个参数中的两个传递给 concat
来忽略这些。这很好,但是当您直接将函数作为参数提供给 reduce
时,它将使用所有四个参数,因此您将获得调用的结果 Array.prototype.concat(a, b, currentIndex, arr)
.
此外,您所做的并不是 Array.prototype
的合理使用。 concat
函数连接其参数并将它们附加到 this
值的副本。由于 Array.prototype
本身只是一个空数组(尽管有许多其他数组用作继承属性的自有属性),这实际上与 [].concat(a,b)
或(可能更易读)a.concat(b)
.