检测未绑定的本机函数,如`Array.push`?

时间:2012-08-20 12:54:53

标签: javascript

请注意以下事项:

function array_map(array, callback) {
    for (var i = 0; i < array.length; i += 1) {
        callback(array[i]);
    }
}
var a = [], b = [];

array_map([1, 2, 3], function (x) { a.push(x); });
// just gives a = [1, 2, 3] as expected

// but why does this not work: ?
array_map([1, 2, 3], b.push);
// Chrome: a = [], Firefox: can't convert undefined to object

执行了解为什么会发生这种情况,即:push如果将其传递给{{1},则不再绑定到b(但对全局对象)直接我真的不明白为什么Chrome不会出错,至少Firefox似乎会出现某种错误。

如何检测此类函数是否传递给array_map以避免这些错误

我希望有先进的反射技术来跟踪函数的来源。例如array_map给出了b.push.constructor,但这不是我想要的。

3 个答案:

答案 0 :(得分:2)

我不确定你期望会发生什么。 Array.prototype.map需要一个函数作为第二个参数,它会为每次迭代返回 new 值。

仅传入函数引用(在第二个示例中执行)并不会告诉函数它无论如何都要执行。所以你有点期待.map()应用一些黑魔法并使用正确的参数调用传入的方法,显然,这是不可能的。

我完全不知道你编写了自己的映射函数。但是,您的问题是您正在丢失该.push()函数的范围。只有当您在Array / Object xxx.push()上调用它时,被调用函数中的this才能正确引用目标对象。在您完成参考后,this将指向全局 / windowundefined,并且将不再有效。

所以解决这个问题你可以称之为

array_map([1, 2, 3], b.push.bind(b));

也适用于ES5功能。您无法在array_map()内真正检测到它。函数是一个函数,你最好的方法是检测传入的方法是否是本机的,但我不建议这样做。

答案 1 :(得分:1)

问题是,Javascript没有“方法”这样的东西 - 一个专门绑定到某个对象的函数。在第一个示例中,您传递了一个调用a.push的函数。 this绑定到a,因为您直接在。

上调用它

在第二个代码中,您只需传递函数push,而不会将b - this的上下文绑定到执行上下文,这是gloabl对象。

您需要绑定函数的上下文,如下所示:

array_map([1, 2, 3], b.push.bind(b));

或jQuery的proxy()。我目前找不到另一个简单的解决方案,而是直接在第三个参数中移交上下文:function array_map(array, callback, context)

答案 2 :(得分:1)

通常这些类型的函数允许您设置回调的上下文。

如果更改array_map函数以接受上下文,那么它将像这样工作。

function array_map(array, callback, context) {
    for (var i = 0; i < array.length; i += 1) {
        callback.call(context, array[i]);
    }
}
var b = [];

// now the push method is called from the b context
array_map([1, 2, 3], b.push, b);