Javascript 如何在javascript中实现观察者模式?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12308246/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to implement observer pattern in javascript?
提问by Ignacio Garat
Hi I'm tyring to implement observer pattern in JavaScript:
嗨,我很想在 JavaScript 中实现观察者模式:
My index.js:
我的 index.js:
$(document).ready(function () {
var ironMan = new Movie();
ironMan.setTitle('IronMan');
ironMan.setRating('R');
ironMan.setId(1);
// ironMan.setCast(['Robert Downey Jr.', 'Jeff Bridges', 'Gwyneth Paltrow']);
var terminator = new Movie();
terminator.setTitle('Terminator');
terminator.setRating('P');
terminator.setId(2);
console.log(ironMan.toString());
console.log(terminator.toString());
ironMan.play();
ironMan.stop();
ironMan.download();
ironMan.share('V. Rivas');
console.log(ironMan.getCast()[0]);
});
My movie:
我的电影:
var title;
var rating;
var id;
var observers;
function Movie() {
observers = new ObserverList();
}
//function Movie (title, rating, id){
// this. title = title;
// this.rating = rating;
// this.id =id;
// observers = new ObserverList();
//}
Movie.prototype.setTitle = function (newTitle) {
this.title = newTitle;
}
Movie.prototype.getTilte = function () {
return this.title;
}
Movie.prototype.setRating = function (newRating) {
this.rating = newRating;
}
Movie.prototype.getRating = function () {
return this.rating;
}
Movie.prototype.setId = function (newId) {
this.id = newId;
}
Movie.prototype.getId = function () {
return this.id;
}
Movie.prototype.play = function () {
for (i = 0; i < observers.Count; i++) {
console.log("palying...");
}
}
Movie.prototype.stop = function () {
for (i = 0; i < observers.Count; i++) {
console.log("stoped");
}
}
Movie.prototype.AddObserver = function (observer) {
observers.Add(observer);
};
Finally observer:
最后观察者:
function ObserverList() {
this.observerList = [];
}
ObserverList.prototype.Add = function (obj) {
return this.observerList.push(obj);
};
ObserverList.prototype.Empty = function () {
this.observerList = [];
};
ObserverList.prototype.Count = function () {
return this.observerList.length;
};
ObserverList.prototype.Get = function (index) {
if (index > -1 && index < this.observerList.length) {
return this.observerList[index];
}
};
ObserverList.prototype.Insert = function (obj, index) {
var pointer = -1;
if (index === 0) {
this.observerList.unshift(obj);
pointer = index;
} else if (index === this.observerList.length) {
this.observerList.push(obj);
pointer = index;
}
return pointer;
};
Any help you can provide will me most grateful.
你能提供的任何帮助我都会非常感激。
采纳答案by Dmitry Osinovskiy
In JavaScript, there is no point to implement pure observer pattern as in Java, because JavaScript has this little thing called functional programming. So just use something like http://api.jquery.com/category/callbacks-object/instead of your ObserverList.
在 JavaScript 中,没有必要像在 Java 中那样实现纯观察者模式,因为 JavaScript 有一个叫做函数式编程的小东西。所以只需使用类似http://api.jquery.com/category/callbacks-object/ 的东西,而不是你的 ObserverList。
If you still want to use your object, then everything depends on what do you want to pass to ObserverList.Add. If it is some object, then you need to write
如果您仍然想使用您的对象,那么一切都取决于您要传递给 ObserverList.Add 的内容。如果是某个对象,那么你需要写
for( i = 0; i < observers.Count; i++) {
observers[i].Notify("some data");
}
If it is a function then you need to write
如果它是一个函数,那么你需要写
for( i = 0; i < observers.Count; i++) {
observers[i]("Some data");
}
Also you can use Function.apply() or Function.call() to supply this
to your function
您也可以使用 Function.apply() 或 Function.call() 来提供this
给您的函数
回答by d13
JavasScript is event-driven: That means it's aware of time and expects things to change over time. The original Observer Pattern was created for languages like C++ that aren't aware of time. You can leverage JavaScript's strengths by using a game loopto check for state changes.
JavaScript 是事件驱动的:这意味着它知道时间并期望事情会随着时间而改变。最初的观察者模式是为像 C++ 这样不知道时间的语言创建的。您可以通过使用游戏循环来检查状态更改来利用 JavaScript 的优势。
Create two DOM elements, an input and output
创建两个 DOM 元素,一个输入和一个输出
<input type="text" value="Enter some text...">
<p id="output">
Set up a requestAnimationFrame
loop and start observing.
建立一个requestAnimationFrame
循环并开始观察。
//Get a reference to the input and output
var input = document.querySelector("input");
var output = document.querySelector("#output");
//Set up a requestAnimationFrame loop
function update () {
requestAnimationFrame(update);
//Change the output to match the input
output.innerHTML = input.value;
}
update();
This is what game engines do for immediate moderendering. It's also what the React framework does to check for state changes in the DOM.
这就是游戏引擎为即时模式渲染所做的。这也是 React 框架用来检查 DOM 中状态变化的作用。
(If you need it, here's a simple requestAnimationPolyfill)
(如果你需要,这里有一个简单的 requestAnimationPolyfill)
//Polyfill for requestAnimationFrame
window.requestAnimationFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
回答by curran
Here's an implementation of the Observer pattern in JavaScript that provides an API very similar to Backbone Models. This implementation avoids use of "this" and "new", as suggested by Douglas Crockford.
这是 JavaScript 中观察者模式的一个实现,它提供了一个与Backbone Models非常相似的 API 。正如Douglas Crockford所建议的那样,此实现避免使用“this”和“new” 。
// The constructor function.
function Model(){
// An object containing callback functions.
// * Keys are property names
// * Values are arrays of callback functions
var callbacks = {},
// An object containing property values.
// * Keys are property names
// * Values are values set on the model
values = {};
// Return the public Model API,
// using the revealing module pattern.
return {
// Gets a value from the model.
get: function(key){
return values[key];
},
// Sets a value on the model and
// invokes callbacks added for the property,
// passing the new value into the callback.
set: function(key, value){
values[key] = value;
if(callbacks[key]){
callbacks[key].forEach(function (callback) {
callback(value);
});
}
},
// Adds a callback that will listen for changes
// to the specified property.
on: function(key, callbackToAdd){
if(!callbacks[key]){
callbacks[key] = [];
}
callbacks[key].push(callbackToAdd);
},
// Removes a callback that listening for changes
// to the specified property.
off: function(key, callbackToRemove){
if(callbacks[key]){
callbacks[key] = callbacks[key].filter(function (callback) {
return callback !== callbackToRemove;
});
}
}
};
}
Here's some example code that uses Model:
下面是一些使用模型的示例代码:
// Create a new model.
var model = Model();
// Create callbacks for X and Y properties.
function listenX(x){
// The new value is passed to the callback.
console.log('x changed to ' + x);
}
function listenY(y){
// The new value can be extracted from the model.
console.log('y changed to ' + model.get('y'));
}
// Add callbacks as observers to the model.
model.on('x', listenX);
model.on('y', listenY);
// Set values of X and Y.
model.set('x', 30); // prints "x changed to 30"
model.set('y', 40); // prints "y changed to 40"
// Remove one listener.
model.off('x', listenX);
model.set('x', 360); // prints nothing
model.set('y', 50); // prints "y changed to 40"
回答by zak.http
Below is an implementation i adapted a little from the book Learning Javascript Design Patterns.
下面是我从《学习 Javascript 设计模式》一书中改编的一个实现。
function pubsub(obj) {
var events = {},
subUid = -1;
obj.publish = function (event, args) {
if (!events[event]) {
return false;
}
var subscribers = events[event],
len = subscribers ? subscribers.length : 0;
while (len--) {
subscribers[len].func(event, args);
}
};
obj.subscribe = function (event, func) {
if (!events[event]) {
events[event] = [];
}
var token = (++subUid).toString();
events[event].push({
token: token,
func: func
});
return token;
};
obj.unsubscribe = function (token) {
for (var event in events) {
if (events.hasOwnProperty(event)) {
for (var i = 0, j = events[event].length ; i < j ; i++) {
if (events[event][i].token === token) {
events[event].splice(i, 1);
}
}
}
}
return this;
};
}
var obj = {}; // Any javascript object
pubsub(obj); // Make an observable from the given object
var subscription = obj.subscribe('load', handler);
// event handler callback
function handler(event, data) {
console.log(event, data);
}
obj.publish('load', 'Data loaded successfully'); // logs 'load Data loaded successfully'
obj.unsubscribe(subscription);
obj.publish('load', 'Data loaded successfully'); // nothing happens
Cheers!
干杯!
回答by zloctb
class EventObserver {
constructor () {
this.observers = []
}
subscribe (fn) {
this.observers.push(fn)
}
unsubscribe (fn) {
this.observers = this.observers.filter(subscriber => subscriber !== fn)
}
broadcast (data) {
this.observers.forEach(subscriber => subscriber(data))
}
}
Or you can use EventEmitter in NodeJs https://nodejs.org/api/events.html#events_class_eventemitter
或者你可以在 NodeJs 中使用 EventEmitter https://nodejs.org/api/events.html#events_class_eventemitter
回答by GutiMac
For me this is the best way to implement an Observer pattern in JS
对我来说,这是在 JS 中实现观察者模式的最佳方式
function Click() {
this.handlers = []; // observers
}
Click.prototype = {
subscribe: function(fn) {
this.handlers.push(fn);
},
unsubscribe: function(fn) {
this.handlers = this.handlers.filter(
function(item) {
if (item !== fn) {
return item;
}
}
);
},
fire: function(o, thisObj) {
var scope = thisObj || window;
this.handlers.forEach(function(item) {
item.call(scope, o);
});
}
}
// log helper
var log = (function() {
var log = "";
return {
add: function(msg) { log += msg + "\n"; },
show: function() { alert(log); log = ""; }
}
})();
function run() {
var clickHandler = function(item) {
log.add("fired: " + item);
};
var click = new Click();
click.subscribe(clickHandler);
click.fire('event #1');
click.unsubscribe(clickHandler);
click.fire('event #2');
click.subscribe(clickHandler);
click.fire('event #3');
log.show();
}
回答by B T
The observer pattern is all about updating an object and having those updates automatically send out an event that gives info about what was updated.
观察者模式是关于更新一个对象并让这些更新自动发送一个事件,该事件提供有关更新内容的信息。
For example:
例如:
function ObserverList(){
this.observerList = []
this.listeners = []
}
ObserverList.prototype.add = function( obj ){
this.observerList.push(obj)
this.listeners.forEach(function(callback){
callback({type:'add', obj:obj})
})
}
ObserverList.prototype.onChange = function(callback){
this.listeners.push(callback)
}
Here's a module of the observer pattern in javascript, you can take a look at the source code fore more info: https://github.com/Tixit/observe
这是javascript中观察者模式的一个模块,您可以查看源代码以获取更多信息:https: //github.com/Tixit/observe
回答by Joey Guerra
This is old, but I wanted to provide an answer to the original question, "how to implement the observer pattern given the existing code".
这是旧的,但我想提供原始问题的答案,“如何在给定现有代码的情况下实现观察者模式”。
The Observer pattern can be simplified as a communication design where the target (the thing being observed) has a pointer to the observer(s) and assumes a public API for an observer. For example, the target assumes that an observer has a method called update
or that an observer is a Function
. It's how a target notifies observers of changes, by actually calling a method on the observer object (or Function
if the observer is a function).
观察者模式可以简化为一种通信设计,其中目标(被观察的事物)有一个指向观察者的指针,并为观察者假定一个公共 API。例如,目标假设观察者有一个被调用的方法update
或观察者是一个Function
。这是目标通过实际调用观察者对象上的方法(或者Function
如果观察者是一个函数)来通知观察者变化的方式。
Any time a property is mutated or changed, the target must update
all observers that have registered to be notified.
每当属性发生变异或更改时,目标必须update
通知所有已注册的观察者。
Here, I'm assuming that you want to know how to implement a Key-Value Observer. In which case, the code will have to iterate over its observer list and call each observers update
method (or just execute the observer in the case where it's a Function
) when a property is changed.
在这里,我假设您想知道如何实现 Key-Value Observer。在这种情况下,代码将不得不遍历其观察者列表并在属性更改时调用每个观察者update
方法(或者在它是 a 的情况下只执行观察者Function
)。
var observers = null;
function Movie() {
observers = new ObserverList();
}
Movie.prototype.changed = function(key, old, value){
// Assumption here is that observers can observe individual properties.
if(!this.observers[key]) return
this.observers[key].forEach( o => {
// Assumption is that observers have an update method. This is the only
// thing the target knows about an observer.
o.update(key, old, value, this)
})
}
// Now every setter on the target has to notify the observers by calling `changed`
Movie.prototype.setTitle = function (newTitle) {
var old = this.title;
this.title = newTitle;
this.changed("title", old, this.title, this)
}
you'd have to add that changed
method and then update all the setter methods to call changed as per above.
您必须添加该changed
方法,然后更新所有要调用的 setter 方法,如上所述。
I also noticed that there's nowhere in the original code that observes
the movie. You'll need to add code that actually observes
it, something that implements update
, given my example above.
我还注意到observes
电影的原始代码中没有任何地方。根据我上面的示例,您需要添加实际的代码,observes
即实现 的代码update
。
I'm unsure what the intent is for play
and stop
.
我不确定play
and的意图是什么stop
。