我是否正确使用Javascript回调(面向对象的风格)?

时间:2011-01-18 19:35:39

标签: javascript callback oop

我有以下代码示例来使用从回调接收操作的对象。看起来这不是一个好的设计模式。或者是吗?

setTimeOut()在1秒后触发函数时,它使用objInstance全局变量(DOM作用域)来访问ClassExample对象实例。有人可以推荐一种更好的方法来在面向对象的设计中使用回调吗?

整个想法是这样我可以使用回调来更新我的对象实例中的数据(例如增加一个变量)。

function ClassExample{
    this.initiate = function() {
        setTimeOut(objInstance.afterTimeOut,1000); //using the objects global handle
    }

    this.afterTimeOut = function() {
        alert("Received!");
    }

}

var objInstance = new ClassExample(); //instance
objInstance.initiate();

6 个答案:

答案 0 :(得分:4)

不,你不是。你会想要这样做:

this.initiate = function() {
    setTimeOut(objInstance.afterTimeOut,1000); //using the objects global handle
}

现在,如果“afterTimeout”需要正确的对象上下文,您可以这样做:

this.initiate = function() {
  var instance = this;
  setTimeout(function() { instance.afterTimeOut(); }, 1000);
}

<击>

好吧,你用这个小编辑大大改变了问题:-)如果我是你,我会这样做(就像我原来的第二个例子):

this.initiate = function() {
  var instance = this;
  setTimeout(function() { instance.afterTimeOut(); }, 1000);
}

然后你根本不需要任何丑陋的全局变量。

编辑 - Stackoverflow用户@Christoph评论说这不是特别漂亮。可能有用的一件事是使用“绑定”工具,由本地较新的浏览器(作为Function原型上的方法)或某些库(例如Prototype或Functional)提供。什么“绑定”让你做的是创建一个小包装函数,就像我上面的那样:

this.initiate = function() {
  setTimeout(this.afterTimeOut.bind(this), 1000);
}

对“bind”的调用返回的函数实际上与我在示例中明确编码的小包装器相同。

答案 1 :(得分:2)

function ClassExample{
    this.afterTimeOut = function() {
        alert("Received!");
    }; // Don't forget these

    setTimeOut(afterTimeOut, 1000); // Don't use () if you're passing the function as an argument
}

var objInstance = new ClassExample(); //instance

这样您就不需要initiate()方法。


如果你真的想要initiate()方法,我会这样做:

function ClassExample{
    var self = this;

    self.afterTimeOut = function() {
        alert("Received!");
    };

    self.initiate = function() {
        setTimeOut(self.afterTimeOut, 1000);
    };

}

var objInstance = new ClassExample(); //instance
objInstance.initiate();

答案 2 :(得分:1)

我这样做是为了让计时器重用并最小化闭包次数:

function Timer(timeout, callback) {
    this.timeout = timeout;
    this.callback = callback;
}

Timer.prototype.run = function(thisArg /*, args... */) {
    var argArray = Array.prototype.slice.call(arguments, 1);
    var timer = this;

    setTimeout(function() {
        timer.callback.apply(thisArg, argArray);
    }, timer.timeout);
};

var timer = new Timer(1000, alert);
timer.run(null, 'timer fired!');

只是为了好玩,这是一个功能相当的高尔夫版本,但用一个封盖代替了这个对象:

function delay(func, timeout) {
    return function() {
        var self = this, args = arguments;
        setTimeout(function() { func.apply(self, args); }, timeout);
    };
}

delay(alert, 1000).call(null, 'timer fired!');

答案 3 :(得分:0)

你是对的,这不是做你所瞄准的最佳方式。但是我不得不想知道为什么你需要打破callstack作为启动的一部分,它似乎非常学术化。

除此之外,如果我必须这样做,我可能会使用这样的闭包:

function ClassExample{
    this.initiate = function() {
        setTimeOut((function(self) { return function() { self.afterTimeout();}})(this),1000); //using the objects global handle
    }

    this.afterTimeOut = function() {
        alert("Received!");
    }

}

var objInstance = new ClassExample(); //instance
objInstance.initiate()

答案 4 :(得分:0)

this.initiate = function() {
    var instance = this;
    setTimeOut(function() {
        instance.afterTimeOut();
    }, 1000);
};

通过将this保存到本地变量,您可以完全避免使用全局句柄。这也可以防止afterTimeout()丢失this

答案 5 :(得分:0)

以Znarkus为基础回答......

我真的不知道他的代码在哪个环境中运行但对我来说第一种方法是行不通的。我得到了:&#39; ReferenceError:未定义afterTimeOut &#39; ...

然而,第二个真的很酷......我刚刚为setTimeout更改了setTimeOut(使用小写&#39; o&#39;)并在类名定义后将括号括起来将第一行代码转换为&# 39; function ClassExample(){&#39 ;;解决了我的问题。

我的示例代码片段:

Oop有私人行为,实习生回拨电话等等。

function MyTry (name){
   // keep this object pointer... that's the trick!
   var self = this;

   // create private variable
   var d = new Date()toJSON().slice(0, 10);

   // create a private function
   function getName(){return name}

   // create public access method
   self.hello  = function(){alert('Hello '+getName()+'!\nToday is: '+d)}

   // note instance method hello passed as a callback function!
   self.initiate = function(){setTimeout(self.hello, 3000)}
}