为什么bind()或apply()在这里工作,但call()呢?

时间:2013-11-27 15:22:43

标签: javascript javascript-events binding prototype

采用我正在尝试的这个非常简单的框架(这样我就可以更深入地学习JavaScript的函数原型。)

(function(){
var app = {
    ui: {
        app: document.querySelector('.app'),
        settings: document.querySelector('.settings'),
    },
    actions: 'click settings openSidebar'
    ,
    functions: {
        openSidebar: function(e){
            console.log(this); // <- expected value of this is 'app.ui'
        }
    },
    run: function(){
        var a1 = this.actions.split("\n");
        var a2 = this.actions.split(" ");

        var self = this;
        this.ui[a2[1]].addEventListener(a2[0], function(e){
            app.functions.openSidebar.call(self.ui,e);
        });
    }
};
app.run();
})();

这很有效。控制台的输出是:

Object {ui: Object, actions: "click settings openSidebar", functions: Object, run: function}

然而,当我尝试这样做时:

var self = this;
this.ui[a2[1]].addEventListener(a2[0], function(e){
    app.functions.openSidebar(e);
}.bind(this));

thisopenSidebar()的上下文是openSidebar(又名绑定无效)。控制台输出:

Object {openSidebar: function}

但是,当我尝试使用apply函数时,如下所示:

app.functions.openSidebar.apply(self.ui,e);

一切正常(openSidebar中的thisapp.ui)除了参数(e)没有通过外,所以e == undefined

这里是:

1。为什么在第一个例子中没有绑定工作(根本没有)?

2。为什么在没有传递参数的情况下应用工作(e(事件))?

添加布朗尼点:

第3。为什么呼叫按预期工作?

2 个答案:

答案 0 :(得分:1)

  1. 您需要这样做:

    this.ui[a2[1]].addEventListener(a2[0], app.functions.openSidebar.bind(this));

  2. bind返回一个新函数,其中包含您传入的任何内容的手动设置上下文。因为您没有在正确的函数上使用bind,所以您在调用的左侧使用app.functions调用函数函数,此后在调用函数中称为this

    1. Apply将参数作为数组,而不是命名参数......

    2. 我不能解释第三个,而不是说呼叫是如何工作的!

答案 1 :(得分:1)

  

为什么在第一个例子中没有绑定工作(根本没有)?

它“有效”,它没有按照你的期望做到。

您的匿名函数this内部确实是bind设置的值。但是,当您调用同时也是对象属性(functions.openSidebar)的函数时,对于该调用this会自动绑定到函数内的该对象(即this === functions)。来自父上下文的this的值永远不会在调用链中“继承”。

  

为什么在没有传递参数的情况下应用工作(e(事件))?

因为apply试图通过将其视为数组来从其自己的第二个参数e中提取调用的参数。这意味着首先检查其length属性;您的事件对象没有length,因此apply会生成undefined值,并且有效地表现得像传入一个空数组一样。请参阅annotated ES5 reference for the details

  

为什么呼叫按预期工作?

这是一个奇怪的问题。为什么有效?你正在使用它,就像它的用途一样。