"这"在javascript对象中,闭包表现不一致

时间:2014-05-05 03:50:25

标签: javascript html5 this scope

所以,这可能是在这个网站的某个地方回答的,但我找不到它,如果是的话。

我无法弄清楚为什么在创建对象时我的函数内部的this引用似乎已被解析,而当我调用其中包含引用的函数时,我的函数就被解析了。这是一些代码:

function MyObj (name) {
    this.locked = false;
    this.name = name;
    this.elem = null;
    this.func1 = function () {
        if (this.locked) return;
        /* code that changes this.name here */
        this.elem.innerHTML = this.name;
    };
    this.func2 = function () {
        this.locked = !this.locked;
        if (this.locked) this.elem.className = "locked";
        else this.elem.className = "unlocked";
    };
}

var myObjGlobal = new MyObj("foo");

function callFunc1 () {
    myObjGlobal.func1();
}

然后我有一个在文档加载时调用的函数:

function onLoad() {
    var myElem = document.getElementById("myElem");
    myObjGlobal.elem = myElem;
    myElem.onclick = myObjGlobal.func2;
    document.getElementById("myButton").onclick = callFunc1;
}

我确保所有的html元素都有正确的ID。当我点击myButton时,我没有收到任何错误。但是,当我点击myElem时,我会得到Uncaught TypeError: Cannot set property 'className' of undefined

为什么在调用函数时设置第一个this,在创建对象时设置第二个this? (或者似乎呢?)

这是显示问题的working jsfiddle(使用给定的示例代码)。

提前致谢!

2 个答案:

答案 0 :(得分:3)

myElem.onclick = myObjGlobal.func2;

这并不是你认为的JavaScript所做的。它没有给你func2对象"附加"以任何方式;它只是给你func2。当它稍后被调用时,它被称为myElem的方法,因此this是什么。

这是JS中一个巨大且可怕的瑕疵。 :)

您可以将其包装在另一个函数中:

myElem.onclick = function() {
    myObjGlobal.func2();
};

或者使用.bind,它实际上做同样的事情,现在普遍支持几乎

myElem.onclick = myObjGlobal.func2.bind(myObjGlobal);

另请注意,分配给onclick有点粗鲁,因为您将破坏任何现有的点击处理程序。您可能需要addEventListener

答案 1 :(得分:2)

myElem.onclick = myObjGlobal.func2;

这完全失去了myObjGlobal; myObjGlobal.func2只是一个函数,没有任何东西将this绑定到任何东西上。在JavaScript中,函数的this在被调用时确定,而不是在定义时确定。这是JavaScript的一个非常有用的功能,比Python更直观。调用myElem.onclick时,系统会调用this绑定myElem

Function.prototype.bind是一个实用程序,用于执行您使用callFunc1执行的操作,顺便说一下:

myElem.onclick = myObjGlobal.func2.bind(myObjGlobal);