为什么会抛出一个未定义的异常?

时间:2015-08-12 23:13:23

标签: javascript

var x = []
var y = []
x.forEach (y.push)

如果x非空,第3行将抛出Uncaught TypeError: Array.prototype.push called on null or undefined

var x = [ 1 ]
var y = []
x.forEach (y.push)

注意: x.forEach将3个参数传递给y.push,其中1个为y。明确地这样做不会导致错误。

y.push (1, 1, y)

将y.push包装在匿名函数中将防止错误,即使所有参数都通过。据我所知,所应用的参数数量并不重要。

x.forEach (function (a, b, c, d, e, f, g, h, i, j) {
  y.push (a, b, c, d, e, f, g, h, i, j)
})

使用null和undefined显式调用y.push不会导致错误,即使尝试使用其他可选参数进行欺骗也是如此。

y.push (1, 2, 3, undefined, 5, 6, null, 7, 8)

1 个答案:

答案 0 :(得分:8)

因为当您将y.push传递给.forEach()时,它会丢失y上下文,而当this时,您只会获得.forEach()不合适值的推送方法调用它。

您可以通过绑定对象来使其工作:

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

这当然还有其他问题,因为forEach()传递了多个.push()将会获得的参数。所以,你真的无法成功地使用这种简短形式来组合数组。

当您执行类似

的操作时
var y = [];
var m = y.push;

此时,m === Array.prototype.pushm中的方法没有绑定对象。这是Javascript的一个微妙之处,它可以绊倒很多,但当你真正了解内部的内容时,它确实开始有意义。

.push()只是对象的一个​​属性,所以当你将该属性放入变量或将其作为参数传递时,它就是它自己的值,此时不再有任何关联用你得到它的对象。

因此,要在从对象抓取它之后适当地使用它,您必须将其绑定到具有.call().apply().bind()之类的对象才能使用它在那个对象上。

如果你要做的就是将所有x元素复制到y的末尾,有很多方法可以做到这一点。你可以这样做:

y.push.apply(y, x);

由于.push()需要多个参数,因此您只需将整个x数组传递给.push()

在ES6中,这更容易:

y.push(...x);