1

我正在学习发布者/订阅者模式,并做了一个简单的例子来更好地理解它。

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]); });
}

我有一个按钮和部分视图,我试图通过按钮引发一个事件并在部分视图上显示计数。我得到了事件的提升并显示在部分视图上,但唯一的问题是计数

4

1 回答 1

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 而不是 REFERENCE 传递 SCALAR 数据

所以在你的函数中,当它被调用时,你没有传递:

// .Action(c);
Action (reference_to_c) {
    /*...*/.innerHTML = reference_to_c;
    reference_to_c++;
}

你实际上是通过:

// .Action(c);
Action (1) {
    /*...*/.innerHTML = 1;
    1++;
};

JS 中的对象是通过引用传递的。“对象”包括函数和数组。
非对象标量 ( numbers, strings, booleans, 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" });

在这种情况下,播放列表只真正关心更新用户在页面上看到的标题。
音乐播放器正在处理当前可用的歌曲以及当前所处的状态,以及所有其他好东西。

因此,您当前问题的解决方案是以下之一:

  1. 为 Publisher 创建一个属性,c该属性添加到 c 并随后通知其订阅者
  2. c一个Subscriber的property,这里每次Publisher通知Subscriber的时候,加到自己的cproperty里面,然后写出来
  3. 取出( 看起来像c的参数,这样函数的内部就会指向...sloppy,但是可以。ActionAction : function () { /*...*/ }cwindow.c

这三个中的任何一个都可以解决您的问题。

于 2013-04-17T04:18:18.240 回答