github源碼
javascript
在不改變對象自身的基礎上,在程序運行期間給對象動態的添加職責vue
//看一個簡單的例子: Function.prototype.fn = function(fn){ var self = this; return function(){ self.apply(this,arguments); fn.apply(this,arguments); } } function a(){ console.log('我是函數a'); } var copyA = a.fn(function(){ console.log('我是a函數額外的功能'); }) copyA(); // 我是函數a // 我是a函數額外的功能 //監聽數組的變化 var methods=['push','pop','shift','unshift','splice','slice','sort','reverse']; var Method = {}; for(var i=0;i<methods.length;i++){ var method = methods[i]; (function(method){ var original = Array.prototype[method]; Method[method] = function(){ console.log('監聽數組的變化或者操做函數等'); return original.apply(this,arguments); } })(method) } var list = ['a','b','c']; list.__proto__ = Method; list.push('d');//打印:監聽數組的變化或者操做函數等
看一個段來自javascript面向對象編程指南(第二版)中關於裝飾器模式的解釋及其代碼:
裝飾器模式是一種結構型模式,它與對象的建立無關,主要考慮的是如何拓展對象的功能。也就是說,除了使用線性式(父-子-孫)繼承方式以外,咱們也能夠爲一個基礎對象建立若干個裝飾對象以拓展其功能。而後,由咱們的程序自行選擇不一樣的裝飾器,並按不一樣的順序使用它們。在不一樣的程序中咱們可能會面臨不一樣的需求,並從一樣的裝飾器集合中選擇不一樣的子集。
//裝飾一顆聖誕樹 var tree = {}; tree.decorate = function(){ console.log('tree'); } /*接着,再定義 getDecorator()方法,該方法用於添加額外的裝飾器。裝飾器被實現爲構造器函數,都繼承自 tree 對象。*/ tree.getDecorator = function(deco){ tree[deco].prototype = this; return new tree[deco]; }; /*下面來建立3個裝飾器,咱們將它設爲 tree 的一個屬性(以保持全局命名空間的純淨)。 如下對象也提供了 decorate()方法,注意它先調用了父類的decorate()方法。*/ tree.Red = function(){ this.decorate = function(){ this.Red.prototype.decorate(); // console.log(this.Red.prototype); // console.log(this.Red.prototype.decorate); console.log('red'); }; this.name = 'red'; } tree.Blue = function(){ this.decorate = function(){ this.Blue.prototype.decorate(); // console.log(this.Blue.prototype.decorate); //tree['Blue']的原型是tree,因此打印出"tree" console.log('blue'); } this.name = 'blue'; } tree.Angel = function(){ this.decorate = function(){ this.Angel.prototype.decorate(); // console.log(this.Angel.prototype.decorate); console.log('angle'); } this.name = 'angel'; } /*把全部的裝飾器都添加到基礎對象中:*/ tree = tree.getDecorator('Blue'); tree = tree.getDecorator('Angel'); tree = tree.getDecorator('Red'); /*運行:*/ tree.decorate(); //tree //blue //angle //red /*解析: 一、執行tree = tree.getDecorator('Blue'): tree['Blue'].prototype = tree; tree = {decorate: ƒ, name: "blue"} 即tree['Blue']賦值給tree,tree['Blue']的原型指向tree 輸出: "tree" "blue" 二、執行tree = tree.getDecorator('Angel'): tree['Angel'].prototype = tree['Blue'],(這時候tree已經賦值爲tree['Blue']) tree = {decorate: ƒ, name: "Angle"} 即tree['Angel']賦值給tree,tree['Angel']的原型指向tree['Blue'] 輸出: "angel" 三、執行tree = tree.getDecorator('Red'): tree['Red'].prototype = tree['Angel'],(這時候tree已經賦值爲tree['Angel']) tree = {decorate: ƒ, name: "Red"} 即tree['Red']賦值給tree,tree['Red']的原型指向tree['Angel'] 輸出: "red" */ /* 圖解:從下往上依次繼承 tree = {decorate:fn,getDecorator:fn} | tree['Blue'].prototype//tree={decorate: ƒ, name: "blue"} | tree['Angel'].prototype//tree={decorate: ƒ, name: "Angle"} | tree['Red'].prototype//tree={decorate: ƒ, name: "Red"} */
看一個段來自javascript面向對象編程指南(第二版)中關於裝飾器模式的解釋及其代碼:
觀察者模式是一種行爲型模式,主要用於處理不一樣對象
之間的交互通訊問題。觀察者模式中一般會包含兩類對象。java一個或多個發佈者對象:當有重要的事情發生時,會通知訂閱者。一個或多個訂閱者對象:它們追隨一個或多個發佈者,監聽它們的通知,並做出
相應的反應git
var observer = { addSubscriber:function (callback){//添加訂閱者 if(typeof callback === "function"){ this.subscribers[this.subscribers.length] = callback; } }, removeSubscriber:function (callback){//刪除訂閱者 for(var i=0;i<this.subscribers.length;i++){ if(this.subscribers[i] === callback){ delete this.subscribers[i]; } } }, publish:function (what) {//授受並傳遞數據給訂閱者 for(var i=0;i<this.subscribers.length;i++){ if(typeof this.subscribers[i] === "function"){ this.subscribers[i](what); } } }, make:function(o){//將任意對象轉變爲一個發佈者併爲其添加上述方法。 for(var i in this){//this->observer{addSubscriber: ƒ, removeSubscriber: ƒ, publish: ƒ, make:f} if(this.hasOwnProperty(i)){//observer.hasOwnProperty('addSubscriber') -> true o[i] = this[i]; o.subscribers = []; } }//o-> {addSubscriber: ƒ, removeSubscriber: ƒ, publish: ƒ, make:f,subscribers:[],o.XX} } }; //有個函數blogger和任意一個函數jack var blogger = { writeBlogPost : function(){ var content = 'blogger'; this.publish(content); } }; var jack = { read:function (what){ console.log('jack訂閱: '+what); } }; //blogger變爲發佈者 observer.make(blogger); //jack訂閱blogger blogger.addSubscriber(jack.read); //blogger發佈信息 blogger.writeBlogPost(); //輸出:jack訂閱: blogger 最後: 別的函數也能夠成爲發佈者, blogger也能夠添加任意的函數爲訂閱者 jack也能夠訂閱別的發佈者
以上總結爲: 1.指定一個發佈者 2.給發佈者添加緩存列表,存放回調函數,通知訂閱者 3.發佈信息時,發佈者遍歷緩存表,觸發存放的回調函數 下面看個簡單的例子:
var Event = function(){ this.subs = {}; } //添加收聽者: Event.prototype.addSubscriber=function(k,callback){ if(!this.subs[k]){ this.subs[k]=[]; } this.subs[k].push(callback); }; //發佈事件: Event.prototype.publish=function(k,item){ var fns=this.subs[k]; if(fns){//防止發佈給不存在的對象 for(var i=0;i<fns.length;i++){ fns[i](item) } } } function reader(item){ console.log(item); console.log('我是收聽的'); //console.log(arguments) } var event = new Event(); event.addSubscriber('a',reader) event.addSubscriber('b',reader) event.publish('a','publish發佈信息'); event.publish('b','publish發佈信息');//不存在的訂閱事件b
Vue雙向綁定的實現原理系列(一):Object.defineproperty
Vue雙向綁定的實現原理系列(二):設計模式
Vue雙向綁定的實現原理系列(三):監聽器Observer和訂閱者Watcher
Vue雙向綁定的實現原理系列(四):補充指令解析器compilegithub