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

我有这个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指针。 考虑:

 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执行时, this内部start函数指向window对象。 并且window对象没有任何名为fooBar方法并且您得到错误。

匿名function方法:

anonymous function传递给setInterval并从中调用函数是一种很好的做法。 如果您的函数使用它,这将非常有用。

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

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

绑定方法:

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

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