从javascript计时器调用非全局函数

时间:2011-04-01 16:03:28

标签: javascript class timer

是否有可能以某种方式从计时器调用非全局函数(即类的方法)?

以下示例显示了我想要实现的目标:

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

3 个答案:

答案 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中的功能。字符串调用evaleval类似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

祝你好运。