无法使用`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
指针可以指向很多东西中的一个,具体取决于上下文:
- 在构造函数(函数调用以
new
开头)中,this
指向新创建的构造函数实例。 - 当函数被调用为对象的方法(例如
obj.funct()
)时,函数内的this
指针指向对象。 - 您可以使用
call
,apply
或bind
显式设置this
指向的内容。 - 如果以上都不是,则默认情况下
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); }