Using prototype functions in higher order functions in javascript

你。 提交于 2019-12-11 06:58:29

问题


I'm trying to concat an array of arrays using reduce and I figured that I could use the Array.prototype.concat function like this:

arr = [[1],[2],[3]]
arr.reduce((a, b) => Array.prototype.concat(a, b), [])

Which works fine and gives me the array [1, 2, 3]. Then I thought I could be even smarter and do it like this:

arr = [[1],[2],[3]]
arr.reduce(Array.prototype.concat, [])

This however gives me an error:

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)

It seems to think that Array.prototype.concat is undefined. Why is this?


回答1:


concat operates as a method with respect to some object (i.e., the this value of the method's execution). When you pass a function into a function, you do not pass along any this value. Thus, you're effectively doing something similar to:

var rawConcat = Array.prototype.concat;
rawConcat(a,b);

You can use bind to create a copy of a function with a particular this burned into it:

arr.reduce(Array.prototype.concat.bind(Array.prototype), [])

However, now that that's cleared up, there are several other issues that stop you from doing this.

For one, reduce actually gets four arguments, including the current index and the whole array. You ignore these by having your (a,b)=> lambda only pass two of those four arguments into concat. That's fine, but when you supply a function directly as an argument to reduce, it will use all four arguments, so you'll get the result of the call Array.prototype.concat(a, b, currentIndex, arr).

Furthermore, what you're doing isn't a sensible use of Array.prototype. The concat function concatenates its arguments and appends them to a copy of the this value. Since Array.prototype is itself just an empty array (albeit with many own-properties that other arrays use as inherited properties), this is effectively the same as [].concat(a,b) or (perhaps even more readably) a.concat(b).




回答2:


Array.prototype.concat expects the context (this) to be an Array and in your first example the context is actually Array.prototype which incidentally looks exactly like an Array, hence it works.

Your second example however, passes the concat function by reference so the context is null or undefined.

The more correct way to do this would be to use Function.prototype.call to bind the context to one of the arrays or call the method directly on the array, e.g.

arr = [[1],[2],[3]];
arr.reduce((a, b) => Array.prototype.concat.call(a, b), []);

// Or

arr.reduce((a, b) => a.concat(b), []);


来源:https://stackoverflow.com/questions/42541207/using-prototype-functions-in-higher-order-functions-in-javascript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!