是否有可能以某种方式从计时器调用非全局函数(即类的方法)?
以下示例显示了我想要实现的目标:
function MyClass() {
var msg = 'no message';
// shows an alert after some delay
this.delayedAlert = function(message) {
msg = message;
// global function works:
//window.setTimeout('globalShow("'+message+'")', 1000);
// this obviously also works:
//this.show();
// this doesn't work: *************
// I'd like to invoke the show() method of this class after some delay
window.setTimeout('this.show()', 2000);
};
this.show = function() {
alert(msg);
};
}
$(document).ready(function() {
$('p').click(function() {
var c = new MyClass();
c.delayedAlert('hello');
});
});
function globalShow(msg) {
$('#hello').html(msg);
}
您可以在此处找到正在运行的示例:http://jsbin.com/aqako5
答案 0 :(得分:4)
function MyClass() {
var msg = 'no message';
// shows an alert after some delay
this.delayedAlert = function(message) {
msg = message;
window.setTimeout($.proxy(this.show, this), 2000);
};
this.show = function() {
alert(msg);
};
}
请使用setTimeout
中的功能。字符串调用eval
和eval
类似goto
。即猛禽会得到你。
实际发生的是,在setTimeout函数内部,this
值是默认的this
值,即窗口。您需要传递一种代理方法,以便this
成为您想要的this
。
代理正确的this
值的替代模式是:
function MyClass() {
var msg = 'no message';
var that = this;
// shows an alert after some delay
this.delayedAlert = function(message) {
msg = message;
window.setTimeout(function() {
that.show();
}, 2000);
};
this.show = function() {
alert(msg);
};
}
这涉及在单独的变量中“缓存”正确的this
值。您仍然无法直接传递that.show
,因为在不知道this
的情况下将调用该函数。
答案 1 :(得分:2)
这会有所帮助。还要改进你的类:如果你的类没有实例化,它可能会导致问题。如果有人像这样打电话给你的班级会发生什么:
var myClass = MyClass();
this
里面的MyClass
现在是窗口,导致各种问题并将您的属性添加到全局命名空间。
要解决此问题,您需要确保在调用类函数时,使用new
运算符完成此操作。您需要在MyClass
内查看,如果这不是MyClass
的新实例,则强制它成为新实例。使用下面的代码,您可以通过以下方式之一调用此方法,并使它们以相同的方式运行:
var myClass = MyClass();
// or
var myClass = new MyClass();
将您的班级更改为:
function MyClass() {
// if this isn't an instance, make it so:
if (!(this instanceof MyClass)) {
return new MyClass();
}
var _this = $(this);
var msg = 'no message';
var show = function() {
alert(msg);
};
// shows an alert after some delay
this.delayedAlert = function(message) {
msg = message;
window.setTimeout(show, 2000);
};
}
您还可以通过在每次创建MyClass
实例时不创建新的函数定义来改进此代码。将您的方法添加到MyClass
的原型:
(function(window) {
var MyClass = function() {
// if this isn't an instance, make it so:
if (!(this instanceof MyClass)) {
return new MyClass();
}
};
var msg = 'no message';
var show = function() {
alert(msg);
};
MyClass.prototype.delayedAlert = function(message) {
msg = message;
window.setTimeout(show, 2000);
};
window.MyClass = MyClass;
})(window);
答案 2 :(得分:0)
您可以声明一个匿名函数:
window.setTimeout(function () {
this.show();
}, 2000);
而且,根据功能,您可以将函数本身传递给setTimeout
:
window.setTimeout(this.show, 2000);
当您将字符串传递给setTimeout
时,您基本上是在告诉浏览器等待一段时间,然后eval
字符串。
当浏览eval
s "this.show()"
时,它会认为this
引用了全局对象,或window
。
第一个建议使用closures,第二个建议只传递函数本身(没有执行它!),我们可以这样做,因为在JavaScript中,functions are first-class objects并且可以就像任何其他变量一样对待。
请记住,当您使用第二个解决方案时,您正在将方法与其上下文分离。如果你尝试以下......
var msg = 'sadface';
var myObj = {
msg: 'hello world',
greet: function () {
alert(this.msg);
}
};
window.setTimeout(myObj.greet, 2000);
...然后this
中的greet
将不再引用myObj
。它将指向window
。它会提醒sadface
,而不是hello world
。