无法使用`this`访问该对象。 `this`指向`window`对象

时间:2013-03-19 11:41:14

标签: javascript jquery oop object

我有这个Javascript构造函数 -

function TestEngine() {
    this.id='Foo';
}

TestEngine.prototype.fooBar = function() {
    this.id='bar';
    return true;
}

TestEngine.prototype.start = function() {
    this.fooBar();
}

TestEngine.prototype.startMethod = function() {
    inter = setInterval(this.start, 200);
}

var test = new TestEngine();
test.startMethod();

给我这个错误 -

Uncaught TypeError: Object [object global] has no method 'fooBar' 

我尝试console.log并发现当我从this.start内拨打setInterval时,this指向window对象。为什么会这样?

3 个答案:

答案 0 :(得分:4)

this指针可以指向许多内容中的一个,具体取决于上下文:

  1. 在构造函数中(以new开头的函数调用)this指向新创建的构造函数实例。
  2. 当函数被调用为对象的方法(例如obj.funct())时,函数内的this指针指向对象。
  3. 您可以使用thiscallapply明确设置bind指向的内容。
  4. 如果以上都不是,那么this指针默认指向全局对象。在浏览器中,这是window对象。
  5. 在您的情况下,您在this.start内呼叫setInterval。现在考虑setInterval的虚拟实现:

    function setInterval(funct, delay) {
        // native code
    }
    

    了解start未被称为this.start非常重要。它被称为funct。这就像做这样的事情:

    var funct = this.start;
    funct();
    

    现在这两个函数通常都会执行相同的操作,但是有一个小问题 - this指针在第二种情况下指向全局对象,而在第一种情况下指向当前this

    要做的一个重要区别是我们正在谈论this内的start指针。考虑:

    this.start();           // this inside start points to this
    var funct = this.start;
    funct();                // this inside funct (start) point to window
    

    这不是错误。这是JavaScript的工作方式。当您将函数作为对象的方法调用时(请参阅上面的第二点),函数内的this指针指向该对象。

    在第二种情况下,由于funct未被调用为对象的方法,因此默认应用第四个规则。因此this指向window

    您可以通过将start绑定到当前this指针然后将其传递给setInterval来解决此问题,如下所示:

    setInterval(this.start.bind(this), 200);
    

    就是这样。希望这个解释能帮助您更好地理解JavaScript的精彩内容。

答案 1 :(得分:3)

以下是使用javascript进行OOP的简洁方法:

//Global Namespace:
var MyNamespace = MyNamespace || {};

//Classes:
MyNamespace.MyObject = function () {

    this.PublicVar = 'public'; //Public variable
    var _privatVar = 'private'; //Private variable

    //Public methods:
    this.PublicMethod = function () {
    }

    //Private methods:
    function PrivateMethod() {
    }

}

//USAGE EXAMPLE:
var myObj = new MyNamespace.MyObject();
myObj.PublicMethod();

通过这种方式,您可以将方法和变量封装到命名空间/类中,以便更轻松地使用和维护。

因此您可以像这样编写代码:

    var MyNamespace = MyNamespace || {};

    //Class: TestEngine
    MyNamespace.TestEngine = function () {

        this.ID = null;
        var _inter = null;

        //Public methods:
        this.StartMethod = function (id) {
            this.ID = id;
            _inter = setInterval(Start, 1000);
        }

        //Private methods:
        function Start() {
            FooBar();
            console.log(this.ID);
        }

        function FooBar() {
            this.ID = 'bar';
            return true;
        }

    }

    //USAGE EXAMPLE:
    var testEngine = new MyNamespace.TestEngine();
    testEngine.StartMethod('Foo');
    console.log(testEngine.ID);

最初,ID设置为'Foo' 1秒后,ID设置为“bar”

请注意,所有变量和方法都封装在TestEngine类中。

答案 2 :(得分:2)

试试这个:

function TestEngine() {
    this.id='Foo';
}

TestEngine.prototype.fooBar = function() {
    this.id='bar';
    return true;
}

TestEngine.prototype.start = function() {
    this.fooBar();
}

TestEngine.prototype.startMethod = function() {
    var self = this;
    var inter = setInterval(function() {
       self.start();
    }, 200);
}

var test = new TestEngine();
test.startMethod();

setInterval使用窗口上下文调用start函数。这意味着当start执行时,thisstart个函数指向window对象。并且window对象没有任何名为fooBar&的方法。你得到错误。

匿名函数方法:

anonymous function传递给setInterval并从中调用您的函数是一种很好的做法。如果您的函数使用this

,这将非常有用

我做的是,创建了一个临时变量self&当它指向您的TestEngine实例时,为其分配this&用它调用self.start()函数。

现在在start函数内,this将指向您的testInstance&一切都会按预期工作。

绑定方法:

Bind会让您的生活更轻松还提高了代码的可读性。

TestEngine.prototype.startMethod = function() {
  setInterval(this.start.bind(this), 200);
}