在闭包中混淆了这个javascript行为

时间:2013-08-17 16:55:34

标签: javascript

进一步了解Javascript和OO编程,但我不明白这个行为的原因是为什么我的ojbect(myUser无法访问属性this.first_name作为'jon'而是未定义(在屏幕截图中以红色显示)在底部)。这是有问题的代码片段:

function User(first_name, last_name){
    this.first_name=first_name;
    this.last_name=last_name;
}

// left in for completeness
User.prototype = {
    constructor: User,
    sayName: function(){
        console.log("My Name: " + this.first_name + " and " + this.last_name);
    }

}

User.prototype.whoWhat = function(){
    console.log(this.first_name + " I want to tell you now " + Math.random());
}

var myUser=new User('jon', 'johnson');
myUser.sayName();
myUser.whoWhat();
setInterval(myUser.whoWhat, 3000);

这是控制台输出:

enter image description here

3 个答案:

答案 0 :(得分:6)

问题是你的setInterval()回调失去了与你构建的对象的关联。当使用属性值进行函数调用时,函数与对象的关联作为属性值会影响this。在这里,您只是引用该值(即获取对该函数的引用)。当系统调用该函数时,this将是undefined(或window对象,具体取决于“严格”模式。

您可以使用包装函数确保this是正确的值:

  setInterval(function() { myUser.whoWhat(); }, 3000);

在较新的浏览器中,您可以使用名为bind()的函数原型中的方法:

  setInterval(myUser.whoWhat.bind(myUser), 3000);

虽然bind()可以做其他事情,但是(为了你的目的)也有同样的效果。

要记住的关键是,在JavaScript中,函数和对象之间没有长期关系。对函数的引用只是普通的值,没有什么特别的事情发生,因为函数碰巧被定义为原型对象或对象文字的属性。唯一重要的是如何实际调用函数。

答案 1 :(得分:3)

此行为在MDN文档中称为“this”问题:

  

setInterval()执行的代码在单独的执行上下文中运行   到它被调用的函数。结果,这个   被调用函数的关键字将被设置为窗口(或全局)   对象,它不会与函数的this值相同   这叫做setTimeout。

https://developer.mozilla.org/en-US/docs/Web/API/window.setInterval

答案 2 :(得分:2)

当您访问属于某个函数的属性时,如果您直接调用它,或者如果您保留该引用并稍后调用它,则会有所不同。

当你直接调用它时,该对象被用作上下文,但如果你保留引用以供日后使用它不再与该对象相关联,并且当你调用它时,它将被调用全局对象(窗口)作为上下文。

解决方法是在函数中调用方法,以便在setTimeout调用中使用:

setInterval(function(){ myUser.whoWhat(); }, 3000);