Observer model

The Observer pattern: There is a one-to-many relationship between objects, and when one object changes, the change is notified to the other objects, thereby influencing the behavior of the other objects, such as enabling them to update themselves automatically.

The observer pattern should be considered when changes to one object require changes to other objects at the same time, and it does not know exactly how many objects need to be changed.

Publish & subscribe one-to-many

// The theme holds state, which triggers all observer objects. class Subject { constructor() { this.state = 0; this.observers = [] } getState() { return this.state; } setState(state) { this.state = state; this.notifyAllObservers() } notifyAllObservers() { this.observers.forEach(observer => { observer.update() }) } attach(observer){ this.observers.push(observer); }} // Class Observer {constructor(name, subject) {this.name = name; this.subject = subject; this.subject.attach(this) } update() { console.log(`${this.name} update, state: ${this.subject.getState()}`); } // test let s = new Subject(); let o1 = new Observer('o1', s); let o2 = new Observer('o2', s); s.setState(12);Copy the code

The Nodejs EventEmitter

Nodejs EventEmitter is a typical implementation of the observer model. Nodejs’ Events module provides only one object: Events.EventEmitter. The core of EventEmitter is the encapsulation of event triggering and event listener functions.

  • addListener(event, listener)

Adds a listener for the specified event. By default, it is added to the end of the listener array.

  • removeListener(event, listener)

Removes a listener for the specified event. the listener must be a listener already registered for the event. It takes two arguments, the event name and the callback function name.

  • setMaxListeners(n)

By default, EventEmitters outputs warnings if you add more than 10 listeners. SetMaxListeners are used to increase the number of default listeners.

  • once(event, listener)

Registers a single listener for the specified event, that is, the listener is fired at most once, and then the listener is fired immediately.

  • emit(event, [arg1], [arg2], […] )

Each listener is executed in listener order, returning true if the event has a registered listener, false otherwise.

function EventEmitter() { this.maxListeners = 10 this.events = Object.create(null); } / / add time to the event queue head EventEmitter. Prototype. AddListener = function (type, the listener, the prepend) {if (! this.events){ this.events = Object.create(null); } if(this.events[type]) { if(prepend) { this.events[type].unshift(listener); } else { this.events[type].push(listener); } } else { this.events[type] = [listener]; }} / / remove an event EventEmitter. Prototype. RemoveListner = function (type, listener) { if(Array.isArray(this.events[type])) { if(! listener) { delete this.events[type] } else { this.events[type] = this.events[type].filter(e => e ! == listener && e.origin ! = = the listener)}}} / / add event to the event queue, execute only once EventEmitter. Prototype. Once = function (type, the listener) {const only = (... args) => { listener.apply(this, args); this.removeListener(type, listener); } only.origin = listener; this.addListener(type, only); } / / perform certain event EventEmitter. Prototype. Emit = functuion (type,... args) { if(Array.isArray(this.events[type])) { this.events[type].forEach(fn=> { fn.apply(this, args); })}} // Set the maximum number of listeners. EventEmitter.prototype.setMaxListenrs = function(count) { thihs.maxListeners = count; }Copy the code

test

var emitter = new EventEmitter(); Var onceListener = function (args) {console.log(' I can only be executed once ', args, this); } var listener = function (args) {console.log(' I am a listener', args, this); } emitter.once('click', onceListener); emitter.addListener('click', listener); Emitters. Emit ('click', 'parameter '); emitter.emit('click'); emitter.removeListener('click', listener); emitter.emit('click');Copy the code

JavaScript DOM events

document.body.addEventListener('click', function() { console.log('hello world! '); }); Document.body.click () //1, const myEvent = new Event("myEvent"); Function (e){}) // add elem.dispatchEvent(myEvent);Copy the code

Vue responsive

  • When you pass a normal JavaScript object into a Vue instance as the data option

  • Vue iterates through all of the Object’s properties and converts them all into getters/setters using Object.defineProperty.

  • Object.defineproperty is a non-shim feature in ES5, which is why Vue does not support IE8 and earlier browsers.

  • These getters/setters are invisible to the user, but internally they allow Vue to track dependencies and notify changes when the property is accessed and modified.

Each component instance corresponds to a Watcher instance, which records “touched” data properties as dependencies during component rendering. Watcher is then notified when the setter for the dependency fires, causing its associated component to be re-rendered.