无法使用“this”访问对象.“this”指向“窗口”对象

Unable to access the object using `this`. `this` points to `window` object

本文关键字:对象 this 指向 窗口 访问      更新时间:2023-09-26

我有这个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,发现当我从setInterval内部调用this.start时,this指向window对象。为什么会这样?

this指针可以指向许多事物之一,具体取决于上下文:

  1. 在构造函数(函数调用前面有 new (中,this指向新创建的构造函数实例。
  2. 当函数作为对象的方法调用时(例如 obj.funct() (,则函数内的this指针指向该对象。
  3. 您可以使用 callapplybind 显式设置this指向的内容。
  4. 如果以上都不是,则默认情况下this指针指向全局对象。在浏览器中,这是window对象。

在您的情况下,您正在setInterval内部呼叫this.start。现在考虑这个setInterval的虚拟实现:

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

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

var funct = this.start;
funct();

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

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

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的伟大之处。

以下是使用 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 类中。

试试这个:

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被执行时,start函数内部this指向window对象。窗口对象没有任何称为fooBar的方法,你得到错误。

匿名函数方法:

最好将

anonymous function传递给setInterval并从中调用函数。如果您的函数使用 this,这将很有用。

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

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

绑定方法:

Bind将使您的生活更轻松,并提高代码的可读性。

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