Skip to content Skip to sidebar Skip to footer

Why Does This Throw An Undefined Exception?

var x = [] var y = [] x.forEach (y.push) Line 3 will throw Uncaught TypeError: Array.prototype.push called on null or undefined if x is non-empty. var x = [ 1 ] var y = [] x.forEa

Solution 1:

Because when you pass y.push to .forEach(), it loses the y context and you get just the push method with an inappropriate value for this when .forEach() calls it.

You can make it work by binding the object like this:

var x = [];
var y = [];
x.forEach (y.push.bind(y)); // push the x items into y

This, of course has other issues in that forEach() passes more than one argument which .push() will pick up. So, you really can't successfully use this short form to combine arrays.


When you do something like

var y = [];
var m = y.push;

At this point, m === Array.prototype.push. There is no object bound to the method in m. This is a subtlety of Javascript that trips up many, but when you really understand what's going in internally, it does start to make sense.

.push() is just a property on an object, so when you put that property into a variable or pass it as an argument, it's just its own value at that point an no longer has any association with the object that you got it from.

So, to use it appropriately after you grabbed it from an object, you have to bind it to an object with something like .call(), .apply() or .bind() in order to use it on that object.


If all you're trying to do is to copy all the x elements onto the end of y, there are a number of ways to do that. You can do this:

y.push.apply(y, x);

Since .push() takes more than one argument, you can just pass the whole x array to .push().

In ES6, this is even easier:

y.push(...x);

Post a Comment for "Why Does This Throw An Undefined Exception?"