koa2--delegates模块源码解读
2019-03-20 00:05 龙恩0707 阅读(598) 评论(0) 编辑 收藏 举报delegates模块是由TJ大神写的,该模块的作用是将内部对象上的变量或函数委托到外部对象上。
然后我们就可以使用外部对象就能获取内部对象上的变量或函数。delegates委托方式有如下:
getter: 外部对象可以通过该方法访问内部对象的值。
setter:外部对象可以通过该方法设置内部对象的值。
access: 该方法包含getter和setter功能。
method: 该方法可以使外部对象直接调用内部对象的函数。
项目文件如下结构:
|----- 项目 | |-- delegates.js # 委托代理的js | |-- index.js # 入口文件的js
1. getter (外部对象可以通过该方法访问内部对象的值。)
使用方法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 (外部对象可以通过该方法设置内部对象的值。)
使用方法的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功能。)
使用方法的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.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 (该方法可以使外部对象直接调用内部对象的函数。)
使用方法的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; };