【问题标题】:Using bind to ensure method refers to object, but it doesn't seem to be working使用绑定来确保方法引用对象,但它似乎没有工作
【发布时间】:2012-03-06 17:31:17
【问题描述】:

在正确的 Javascript 中进一步进行实验,我正在尝试从另一种方法 (WaitAndSayHello) 运行一种方法 (SayHello)。由于涉及回调,我使用了bind 来确保每个方法中的“this”都指向对象。

pretendThingConstructor = function (greeting) {
    this.greeting = greeting;

    this.SayHello = function() {
        console.log(this.greeting); // Works
    };

    this.WaitAndSayHello = function() {
        setTimeout(function() { 
            console.log(this)  
            this.SayHello() // Fails
        }, 500);
    }
    this.WaitAndSayHello.bind(this); // This bind() doesn't seem to work
}


var pretend_thing = new pretendThingConstructor('hello world');
pretend_thing.SayHello();
pretend_thing.WaitAndSayHello();

代码打印'hello world',然后第二次失败并显示'Object # has no method 'SayHello''。我可以从 console.log 中看到,“this”指的是事件。但是不应该使用 bind() 解决这个问题吗?

我怎样才能使 bind() 工作?

此外,我想干净利落地这样做:即,不要在多个地方引用对象的名称。

【问题讨论】:

    标签: javascript oop methods bind


    【解决方案1】:

    您不能“迟到”.bind()。您需要在函数声明时调用它,例如

    this.WaitAndSayHello = function() {
        setTimeout(function() { 
            console.log(this)  
            this.SayHello() // Fails
        }, 500);
    }.bind(this)
    

    此外,您传递给 setTimeout() 的匿名函数会创建一个新的上下文,因此具有自己的 this 上下文值。

    您需要在变量中保存对“外部this”的引用

    this.WaitAndSayHello = function() {
        var self = this;
    
        setTimeout(function() { 
            console.log(self)  
            self.SayHello() // succeeds
        }, 500);
    }.bind(this)
    

    或者再次使用.bind(),比如

    this.WaitAndSayHello = function() {
        setTimeout(function() { 
            console.log(this)  
            this.SayHello() // succeeds
        }.bind(this), 500);
    }.bind(this)
    

    【讨论】:

    • 谢谢@jAndy,这完美地解释了事情。我总是发现关于 'var self = this' 的东西有点 hacky,所以我使用了第二种解决方案 - 我怀疑它会成为我日常 JS 编程的一部分,所以再次感谢。
    • @nailer:非常欢迎。请记住,.bind() 是 ES5 的一部分,因此它可能无法在旧版浏览器中原生使用。但它很容易填充,并且有很多可用的垫片。
    • 附言。 @jAndy 我认为我们只需一个绑定就可以逃脱 - 在从 setTimeout 调用的函数上。绑定 WaitAndSayHello 是不必要的。您可能希望为下一个人更新您的答案。
    【解决方案2】:

    你应该使用:

    this.WaitAndSayHello.call(this);
    

    this.WaitAndSayHello.apply(this);
    

    applycall 之间的区别在于您将参数传递给被调用函数的方式:想象一下 WaitAndSayHello 收到了一些参数:

    this.WaitAndSayHello = function(toWho, helloMessage){
     ...
    }
    

    使用call,您可以在上下文之后传递参数,就像您正常调用函数一样:

    this.WaitAndSayHello.call(this, 'Bob', 'Hello');
    

    使用apply,您必须将参数作为数组传递:

    this.WaitAndSayHello.apply(this, ['Bob', 'Hello']);
    

    编辑

    抱歉,我读错了您的代码,@jAndy 的答案确实是正确的,但是,使用我的逻辑,您可以执行以下操作:

    this.WaitAndSayHello = function() {
            setTimeout.call(this, function() { 
                console.log(this)  
                this.SayHello() // Fails
            }, 500);
        }
    

    【讨论】:

    • 这将如何改变thissetTimeout 回调中对DOM 窗口的引用?
    猜你喜欢
    • 1970-01-01
    • 2014-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多