我正在学习发布者/订阅者模式,并做了一个简单的例子来更好地理解它。
var Publisher = {
subscribers: {},
Subscribe: function (event, callback) {
if (Publisher[event] && typeof callback === "function") {
if (Publisher.subscribers[event]) {
Publisher.subscribers[event].callbacks.push(callback);
}
else {
Publisher.subscribers[event] = { callbacks: [callback] };
}
}
},
Publish: function (event) {
if (Publisher.subscribers[event].callbacks) {
for (callback in Publisher.subscribers[event].callbacks) {
Publisher.subscribers[event].callbacks[callback].apply(null);
}
}
},
PublishOnClick: function (event, argument) {
Publisher.Publish(event, argument);
}
};
var Subscriber1 = {
initialize: function () {
if (Publisher.Subscribe) {
Publisher.Subscribe("PublishOnClick", Subscriber1.Action);
}
},
Action: function (c) {
document.getElementById('result').innerHTML += "Button Clicked and the count is: " + c;
c++;
}
};
Subscriber1.initialize();
var c = 1;
var fld2 = document.getElementById("myfield2");
if (fld2.addEventListener) {
fld2.addEventListener("click", function() { Publisher.PublishOnClick("PublishOnClick", [c]); }, false);
} else if (fld2.attachEvent) {
fld2.attachEvent("onclick", function() { Publisher.PublishOnClick("PublishOnClick", [c]); });
}
我有一个按钮和局部视图,我试图通过按钮提升事件并在部分视图上显示计数。我得到了事件rasied并显示在局部视图上,但唯一的问题是计数
答案 0 :(得分:2)
从我看到的情况来看,你的问题实际上与发布商 - 订阅者范例没有关系。
我认为你的设置有点令人费解......因为从以下内容的角度来看可能更容易理解:
twitter_feed.tweets = [];
twitter_feed.root_el = document.getElementById("tweets");
twitter_feed.update = function (tweet) {
twitter_feed.tweets.push(tweet);
// demonstration-purposes only -- please don't write live code like this
twitter_feed.root_el.innerHTML += "<p>" + tweet.user + ": \"" + tweet.text + "\"</p>";
};
twitter_data.subscribe("new-tweet", twitter_feed.update);
// some event handler which grabs tweets from AJAX or whatever...
twitter_data.notify("new-tweet", { user : "Me", text : "my new tweet" });
目标是发布者不是对象,而是存在可以发布数据的对象,订阅者不是对象,而是可以对已发布事件做出反应的对象的扩展...
...无论如何,你的代码适用于手头的范例......
...除了:
Action : function (c) { /* ... */ c++; }
问题是JS 通过VALUE传递SCALAR数据,而不是通过REFERENCE传递 。
所以在你的函数中,当它被调用时,你没有通过:
// .Action(c);
Action (reference_to_c) {
/*...*/.innerHTML = reference_to_c;
reference_to_c++;
}
你实际上正在通过:
// .Action(c);
Action (1) {
/*...*/.innerHTML = 1;
1++;
};
JS中的对象通过引用传递。 “对象”包括函数和数组
非对象标量(number
s,string
s,boolean
s,null
,undefined
,NaN
)按值传递,因此如果你有一个参数是标量的函数参数,编辑函数内部的版本不会改变外面的值。
var x = 1,
say_X = function (x) { x += 1; console.log(x); };
say_X(x); // 2;
console.log(x); // 1;
// vs
var obj = { x : 1 },
say_X = function (o) { o.x += 1; console.log(o.x); };
say_X(obj); // 2;
console.log(obj.x); //2;
您真正想要做的是让发布者跟踪计数,或让订阅者跟踪计数,具体取决于这样做的意义。
看看我的Twitter示例,顶部。
twitter_feed
跟踪打印到屏幕上的所有推文是有意义的,这样当新推文进来时,它会被添加到列表中。
最新的twitter_data
并不关心之前的推文,因此在这种情况下,订阅者将跟踪状态,发布者只会在发生更改时监听更改并通知其他人。
在其他情况下,发布商可能有必要跟踪其状态,并向订阅者宣布新状态:
music_playlist.update_track = function (data) {
music_playlist.current_song.innerHTML = data.current_song;
};
music_player.subscribe("song-change", music_playlist.update_track);
music_player.notify("song-change", { current_song: "Sympathy for the Daleks" });
在这种情况下,播放列表只关心更新用户在页面上看到的标题 音乐播放器正在处理当前可用的歌曲以及它当前所处的状态,以及所有其他好东西。
因此,您当前问题的解决方案之一是:
c
设为发布商的属性,该属性会添加到c并在之后通知其订阅者c
属性为Subscriber,每次Publisher通知Subscriber时,它都会添加到自己的c
属性,然后将其写出来c
的参数中取Action
(看起来像Action : function () { /*...*/ }
,以便函数内的c
指向window.c
。 ..sloppy,但有效。这三者中的任何一个都应该解决你的问题。