delegates模塊是由TJ大神寫的,該模塊的做用是將內部對象上的變量或函數委託到外部對象上。
而後咱們就能夠使用外部對象就能獲取內部對象上的變量或函數。delegates委託方式有以下:html
getter: 外部對象能夠經過該方法訪問內部對象的值。
setter:外部對象能夠經過該方法設置內部對象的值。
access: 該方法包含getter和setter功能。
method: 該方法能夠使外部對象直接調用內部對象的函數。git
項目文件以下結構:github
|----- 項目 | |-- delegates.js # 委託代理的js | |-- index.js # 入口文件的js
1. getter (外部對象能夠經過該方法訪問內部對象的值。)api
使用方法demo以下(index.js):數組
const delegates = require('./delegates'); const obj = { xx: { name: 'kongzhi', age: 30, test: function() { console.log('xxxxxxx'); } } }; // 經過delegates將內部對象 xx 委託到外部對象obj上 var d = new delegates(obj, 'xx'); d.getter('name').getter('age').getter('test'); console.log(obj.name); // kongzhi console.log(obj.age); // 30 obj.test(); // xxxxxxx
2. setter (外部對象能夠經過該方法設置內部對象的值。)app
使用方法的demo以下(代碼在index.js內):函數
const delegates = require('./delegates'); const obj = { xx: { name: 'kongzhi', age: 30, test: function() { console.log('xxxxxxx'); } } }; // 經過delegates將內部對象 xx 委託到外部對象obj上 var d = new delegates(obj, 'xx'); d.setter('name').setter('age').setter('test'); // 使用setter後,就能夠在obj對象上直接修改變量或函數的值了 obj.name = '123456'; obj.age = '31'; obj.test = function() { console.log('yyyy'); } /* 在外部對象obj修改完成後,咱們再使用 外部對象[內部對象][變量] 這種方式獲取值, 就能夠看到值更新了 */ console.log(obj.xx.name); // 123456 console.log(obj.xx.age); // 31 obj.xx.test(); // yyyy
3. access (該方法包含getter和setter功能。)ui
使用方法的demo以下this
const delegates = require('./delegates'); const obj = { xx: { name: 'kongzhi', age: 30, test: function() { console.log('xxxxxxx'); } } }; // 經過delegates將內部對象 xx 委託到外部對象obj上 var d = new delegates(obj, 'xx'); d.access('name').access('age').access('test'); // access 該方法既有setter功能,又有getter功能 // 1. 直接使用外部對象 obj, 來訪問內部對象中的屬性 console.log(obj.name); // kongzhi console.log(obj.age); // 30 obj.test(); // xxxxxxx // 2. 使用常規的方法獲取對象的內部的屬性 console.log(obj.xx.name); // kongzhi console.log(obj.xx.age); // 30 obj.xx.test(); // xxxxxxx // 3. 修改內部對象的屬性 obj.name = '2222'; console.log(obj.name); // 2222 console.log(obj.xx.name); // 2222
4. method (該方法能夠使外部對象直接調用內部對象的函數。)spa
使用方法的demo以下:
const delegates = require('./delegates'); const obj = { xx: { name: 'kongzhi', age: 30, test: function() { console.log('xxxxxxx'); } } }; // 經過delegates將內部對象 xx 委託到外部對象obj上 var d = new delegates(obj, 'xx'); d.method('test'); obj.test(); // xxxxxxx
5. fluent
該方法的做用是,若是該方法傳了參數的話,那麼它的含義是修改該變量的值,若是沒有傳入參數的話,那麼
它的做用是獲取該參數的值。
注意:只針對變量有用,若是是函數的話,不建議使用;
以下代碼demo所示:
const delegates = require('./delegates'); const obj = { xx: { name: 'kongzhi', age: 30, test: function() { console.log('xxxxxxx'); } } }; // 經過delegates將內部對象 xx 委託到外部對象obj上 var d = new delegates(obj, 'xx'); d.fluent('name').fluent('age'); // 無參數 獲取該對象的值 console.log(obj.name()); // kongzhi console.log(obj.age()); // 30 // 有參數,就是修改對應的值 obj.name('11111') obj.age(31) console.log(obj.xx.name); // 11111 console.log(obj.xx.age); // 31
二:delegates模塊源碼以下:
/** * Expose `Delegator`. */ module.exports = Delegator; /** * Initialize a delegator. * * @param {Object} proto * @param {String} target * @api public */ /* Delegator 函數接收二個參數,proto指是一個是外部對象,target指外部對象中的一個屬性,也就是內部對象。 首先判斷this是不是Delegator的實列,若是不是實列的話,就直接使用 new 實列化一下。 所以 const xx = Delegator(obj, 'xx') 或 const xx = new Delegator(obj, 'xx') 都是能夠的。 this.proto = proto; 外部對象保存該實列this.proto 中。 this.target = target; 和proto同樣。 this.methods = []; this.getters = []; this.setters = []; this.fluents = []; 如上四個數組做用是 記錄委託了哪些屬性和函數。 */ function Delegator(proto, target) { if (!(this instanceof Delegator)) return new Delegator(proto, target); this.proto = proto; this.target = target; this.methods = []; this.getters = []; this.setters = []; this.fluents = []; } /** * Delegate method `name`. * * @param {String} name * @return {Delegator} self * @api public */ /* method的做用是:該方法能夠使外部對象直接調用內部對象的函數。以下demo: const obj = { xx: { name: 'kongzhi', age: 30, test: function() { console.log('xxxxxxx'); } } }; // 經過delegates將內部對象 xx 委託到外部對象obj上 var d = new delegates(obj, 'xx'); d.method('test'); obj.test(); // xxxxxxx 1. 首先咱們調用 d.method('test'); 就把該test方法存入 this.methods數組中。 2. 該方法返回了一個函數 obj['test'] = function() { return obj['xx']['test'].apply(obj['xx'], arguments); } 3. 最後返回 this, 返回該實例化對象,目的是能夠鏈式調用。 4. 所以就返回了第二步函數。所以當咱們使用 obj.test() 的時候,就會自動調用該函數。而後 使用 apply方法自動執行 obj['xx']['test'].apply(obj['xx'], arguments); */ Delegator.prototype.method = function(name){ var proto = this.proto; var target = this.target; this.methods.push(name); proto[name] = function(){ return this[target][name].apply(this[target], arguments); }; return this; }; /** * Delegator accessor `name`. * * @param {String} name * @return {Delegator} self * @api public */ /* 該方法的做用是包含 getter的做用,同時也包含setter的做用,如demo以下: const obj = { xx: { name: 'kongzhi', age: 30, test: function() { console.log('xxxxxxx'); } } }; // 經過delegates將內部對象 xx 委託到外部對象obj上 var d = new delegates(obj, 'xx'); d.access('name').access('age').access('test'); // access 該方法既有setter功能,又有getter功能 // 1. 直接使用外部對象 obj, 來訪問內部對象中的屬性 console.log(obj.name); // kongzhi console.log(obj.age); // 30 obj.test(); // xxxxxxx // 2. 使用常規的方法獲取對象的內部的屬性 console.log(obj.xx.name); // kongzhi console.log(obj.xx.age); // 30 obj.xx.test(); // xxxxxxx // 3. 修改內部對象的屬性 obj.name = '2222'; console.log(obj.name); // 2222 console.log(obj.xx.name); // 2222 */ Delegator.prototype.access = function(name){ return this.getter(name).setter(name); }; /** * Delegator getter `name`. * * @param {String} name * @return {Delegator} self * @api public */ /* getter,該方法的做用是:外部對象能夠經過該方法訪問內部對象的值。好比以下demo const obj = { xx: { name: 'kongzhi', age: 30, test: function() { console.log('xxxxxxx'); } } }; // 經過delegates將內部對象 xx 委託到外部對象obj上 var d = new delegates(obj, 'xx'); d.getter('name').getter('age').getter('test'); console.log(obj.name); // kongzhi console.log(obj.age); // 30 obj.test(); // xxxxxxx 1. 該方法接收一個參數 name, 該參數是一個字符串類型。 2. 把該參數name值保存到 this.getters數組中。而後咱們使用 __defineGetter__ 監聽對象屬性值的變化。 想要理解 __defineGetter__ 做用,請看我這篇文章 (https://www.cnblogs.com/tugenhua0707/p/10324983.html#_labe1) 若是獲取該對象值的話,就會自動調用 __defineGetter__ ,就能監聽到,所以就返回 this[target][name]; 即便: obj['xx']['name']; */ Delegator.prototype.getter = function(name){ var proto = this.proto; var target = this.target; this.getters.push(name); proto.__defineGetter__(name, function(){ return this[target][name]; }); return this; }; /** * Delegator setter `name`. * * @param {String} name * @return {Delegator} self * @api public */ /* 該方法的做用是:外部對象能夠經過該方法設置內部對象的值。使用demo以下: const obj = { xx: { name: 'kongzhi', age: 30, test: function() { console.log('xxxxxxx'); } } }; // 經過delegates將內部對象 xx 委託到外部對象obj上 var d = new delegates(obj, 'xx'); d.setter('name').setter('age').setter('test'); // 使用setter後,就能夠在obj對象上直接修改變量或函數的值了 obj.name = '123456'; obj.age = '31'; obj.test = function() { console.log('yyyy'); } // 在外部對象obj修改完成後,咱們再使用 外部對象[內部對象][變量] 這種方式獲取值, 就能夠看到值更新了 console.log(obj.xx.name); // 123456 console.log(obj.xx.age); // 31 obj.xx.test(); // yyyy 1. 一樣的道理,使用 __defineSetter__方法來監聽對象值發生改變,若是對象值發生改變的話,就返回 this[target][name] = val; 把值賦值進去。最後返回this對象。 */ Delegator.prototype.setter = function(name){ var proto = this.proto; var target = this.target; this.setters.push(name); proto.__defineSetter__(name, function(val){ return this[target][name] = val; }); return this; }; /** * Delegator fluent accessor * * @param {String} name * @return {Delegator} self * @api public */ /* 該方法的做用是,若是該方法傳了參數的話,那麼它的含義是修改該變量的值,若是沒有傳入參數的話,那麼 它的做用是獲取該參數的值。 使用demo以下: const obj = { xx: { name: 'kongzhi', age: 30, test: function() { console.log('xxxxxxx'); } } }; // 經過delegates將內部對象 xx 委託到外部對象obj上 var d = new delegates(obj, 'xx'); d.fluent('name').fluent('age'); // 無參數 獲取該對象的值 console.log(obj.name()); // kongzhi console.log(obj.age()); // 30 // 有參數,就是修改對應的值 obj.name('11111') obj.age(31) console.log(obj.xx.name); // 11111 console.log(obj.xx.age); // 31 1. 當我像如上demo同樣,使用 d.fluent('name').fluent('age');後,會依次保存到 this.flunts數組中。 2. 而後返回一個函數,以下代碼: obj['name'] = function(val) { if ('undefined' != typeof val) { this[target][name] = val; return this; } else { return this[target][name]; } } 若是值沒有傳遞電話,就直接返回 this[target][name]; 即:obj['xx']['name']; 若是傳遞了值的話,就把值賦值到對象裏面去,如代碼:this[target][name] = val; 即:obj['xx']['name'] = val; */ Delegator.prototype.fluent = function (name) { var proto = this.proto; var target = this.target; this.fluents.push(name); proto[name] = function(val){ if ('undefined' != typeof val) { this[target][name] = val; return this; } else { return this[target][name]; } }; return this; };