Subscriber模式中的Javascript范围

时间:2012-03-22 06:03:48

标签: javascript design-patterns

我已经看到了这个问题的解决方案,但似乎无法再找到它......

//
// A simple implementation of the subscriber pattern
//

var Subject = function()
{
    this._observers = [];
};


// Here lies the problem
Subject.prototype.attach = function(observer, func)
{
    this._observers.push(observer);
    this._observers.push(func);
};

// And this only makes the problem worse
Subject.prototype.notify = function(pData)
{
    var len = this._observers.length;
    for(var i = 0; i < len; i += 2)
        this._observers[i][this._observers[i + 1]](pData, this._observers[i]);
};


// Store the data related to the generic Observer
var Observer = function(pId){
    this._el = pId;
};


//
// Notify and Update represent two possible functions that do different stuff
//

Observer.prototype.notify = function(pData, pThis)
{
    document.getElementById(pThis._el).textContent = 'Notify: ' + pData;
};

Observer.prototype.update = function(pData, pThis)
{
    document.getElementById(pThis._el).textContent = 'Update: ' + pData;
};


// In action

var server = new Subject();
var client1 = new Observer('observer_1' /* the ID to some DOM element */);
var client2 = new Observer('observer_2');

// Another manifestation of the problem I've ran into
server.attach(client1, 'notify');
server.attach(client2, 'update');

server.notify('[some data]');

我的问题: 当Subject调用它已注册的所有观察者时,被调用的回调在Subject的上下文中执行。换句话说,何时

Observer.update
调用

,因为它是从Subject内部调用的,是对

的引用
this._el

指的是不存在的Subject._el。我的解决方法是在我的主题中注册2件事:对Observer的引用,以及在Observer中具有回调名称的字符串。然后,当Subject广播通知时,它会调用已注册的回调并向Observer发送对Observer的引用,该引用将被用作:

// instead of this._el (which would refers to server._el,
// do <observer_1>._el

我希望我已经清楚地表达了我的问题,以便得到我需要的帮助。

谢谢!

1 个答案:

答案 0 :(得分:1)

http://jsfiddle.net/UQ3Ay/1/

它的要点是范围。设置回调函数时,必须确保它在观察者的上下文中执行:

// Here lies the problem
Subject.prototype.attach = function(observer, func)
{
    this._observers.push(observer);
    this._observers.push(_.bind(func, observer));
};

最简单的方法是使用underscore.js并更改绑定。您也可以使用call()和apply()创建自己的。

这可能更接近您所寻找的内容:http://jsfiddle.net/UQ3Ay/2/