$.proxy和原生js的'call'/'apply'有什么区别?

9
我认为它们都允许您控制'this'的值,但除此之外,我还有点不清楚,Google/SO目前也没有提供太多帮助。感谢任何澄清。我确实找到了这个,但我对它是否讲述了整个故事持怀疑态度:
“当我第一次了解jQuery的proxy()方法时,我觉得它有点傻;毕竟,Javascript已经有了call()和apply()方法来改变执行上下文。但是,一旦你意识到jQuery的proxy()方法允许您轻松地绑定()和解绑()事件处理程序而不受上下文的影响,就会明显地看出这个方法有多么强大。”

Google-fu的有用搜索术语:JavaScript执行上下文。 - cmbuckley
2
很多jQuery的东西是完全没有意义的。例如许多人认为使用$(this).attr('id')而不是this.id是好的。我没有看过$.proxy,但它很可能也是一样:冗余且无意义的。 - Niet the Dark Absol
@Kolink,这就像你编写一个返回应用程序的函数的函数。几乎每个库都有这种方法。 - epascarello
.proxy 实际上是 bind 的一个 polyfill(即“创建一个绑定到给定上下文的新函数”)。apply 只是实现这一目的的手段。因此,将 .proxyapply/call 进行比较是没有意义的。 - Yoshi
更好的比较是在$.proxy()和新版浏览器中的.bind() API之间进行。(不要与jQuery的.bind()混淆,因为它现在已经被弃用,推荐使用.on()代替。) - Pointy
3个回答

12

call/apply是一次性调用。$.proxy会创建一个永久绑定到某个对象的新函数:

fn.call(foo);  //call once

var otherFn = $.proxy(fn, foo);  // you can call it again later

var otherOtherFn = fn.bind(foo);  // ES5 standard way

作为一种简化(非常简化的)方法,$.proxy创建了一个调用call的新函数:
$.proxy = function(fn, newThis) {
    return function() {
        fn.call(newThis);
    }
}

这类似于 ES5 的 Function.prototype.bind

6

看一下jQuery的源代码:

proxy: function( fn, context ) {
    var tmp, args, proxy;

    if ( typeof context === "string" ) {
        tmp = fn[ context ];
        context = fn;
        fn = tmp;
    }

    // Quick check to determine if target is callable, in the spec
    // this throws a TypeError, but we will just return undefined.
    if ( !jQuery.isFunction( fn ) ) {
        return undefined;
    }

    // Simulated bind
    args = core_slice.call( arguments, 2 );
    proxy = function() {
        return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
    };

    // Set the guid of unique handler to the same of original handler, so it can be removed
    proxy.guid = fn.guid = fn.guid || jQuery.guid++;

    return proxy;
},

如果您删除缓存代码并使其变得更短,您基本上可以获得.apply()(我认为我已经正确翻译了切片代码):
proxy: function(fn, context) {
    var args = [].slice.call(arguments, 2);

    return function() {
        return fn.apply(context || this, args.concat([].slice.call(arguments)));
    };
}

1

$.proxy可以在一个函数上调用,它返回的函数将始终具有特定的上下文。这意味着如果你运行了

$.proxy(function() {console.log(this.val)}, {val: 1}).call({val: 2});

它会记录1,因为该函数始终绑定到最初传递给proxy的对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接