我有这个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
对象。为什么会这样?
答案 0 :(得分:4)
this
指针可以指向许多内容中的一个,具体取决于上下文:
new
开头的函数调用)this
指向新创建的构造函数实例。obj.funct()
)时,函数内的this
指针指向对象。this
,call
或apply
明确设置bind
指向的内容。this
指针默认指向全局对象。在浏览器中,这是window
对象。在您的情况下,您在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
执行时,this
内start
个函数指向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);
}