[javaScript] delegates源码解读
Opened this issue · 0 comments
zgfang1993 commented
- 基本用法
- 源码解读
基本用法:
将内部对象的变量或者函数绑定在暴露在外层的变量上,直接通过 delegates
方法进行如下委托,基本的委托方式包含:
- getter:外部对象可以直接访问内部对象的值
- setter:外部对象可以直接修改内部对象的值
- access:包含 getter 与 setter 的功能
- method:外部对象可以直接调用内部对象的函数
const delegates = require('delegates');
const animal = {
cat: {
name: 'cheese',
age: 1.5,
sex: 'man',
love: 'fish',
speek() {
console.log('miao!');
}
},
}
// 将内部对象 cat 的属性、函数 => 委托至暴露在外的 animal 上
delegates(animal, 'cat')
.getter('name')
.setter('age')
.access('sex')
.method('speek')
.fluent('love');
// 1. 访问内部对象属性
console.log(animal.name) // 'cheese'
// 2. 修改内部对象属性
animal.age = 2;
console.log(animal.cat.age) // 2
// 3. 同时访问和修改内部对象属性
console.log(animal.sex) // 'man'
animal.sex = 'xiaogongong';
console.log(animal.sex); // 'xiaogongong'
// 4. 调用内部对象函数
animal.speek(); // 'miao!'
// 5. 不传参数获取值,传参数修改值,可链式调用
console.log(animal.love()); // 'fish'
console.log(animal.love('mouse').love('maobohe').love()); // 'maobohe'
源码解读
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 = [];
}
methods | getters | setters | flaunts 均为数组,用来记录委托了哪些属性和函数。
如果 this 不是 Delegator 的实例的话,则调用 new Delegator(proto, target)。(避免在调用初始化函数时忘记写 new )。
Delegator(animal, 'cat')
//等价于👇
new Delegator(animal, 'cat')
getter
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;
};
核心:defineGetter
它可以在已存在的对象上添加可读属性, 其中第一个参数为属性名,第二个参数为函数,返回值为对应的属性值。
const obj = {};
obj.__defineGetter__('name', () => 'cheese');
console.log(obj.name); // 'cheese'
obj.name = 'baozi';
console.log(obj.name); // 'cheese' 没有被改名成功
注意:
现在已推荐使用_defineGetter_,建议通过 Object.defineProperty
实现同样功能,或者通过 get
操作符实现类似功能:
const obj = {};
Object.defineProperty(obj, 'name', {
value: 'cheese',
});
Object.defineProperty(obj, 'sex', {
get() {
return 'man';
}
});
const cat = {
get name() {
return 'baozi';
}
};
setter
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;
};
核心:defineSetter
它可以在已存在的对象上添加可读属性, 其中第一个参数为属性名,第二个参数为函数,返回值为对应的属性值。
const obj = {};
obj.__defineSetter__('name', function(value) {
this._name = value;
});
obj.name = 'baozi';
console.log(obj.name, obj._name); // undefined 'baozi'
注意:
现在已推荐使用_defineGetter_,建议通过 Object.defineProperty
实现同样功能,或者通过 set
操作符实现类似功能:
const obj = {};
Object.defineProperty(obj, 'name', {
set(value) {
this._name = value;
}
});
const cat = {
set(value) {
this._name = value;
}
};
method
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;
};
核心:apply
koa中应用
context.request/context.response
的许多属性都被委托在了 context
上。
/**
* Response delegation.
*/
delegate(proto, 'response')
.method('attachment')
.method('redirect')
.method('remove')
.method('vary')
.method('set')
.method('append')
.method('flushHeaders')
.access('status')
.access('message')
.access('body')
.access('length')
.access('type')
.access('lastModified')
.access('etag')
.getter('headerSent')
.getter('writable');
/**
* Request delegation.
*/
delegate(proto, 'request')
.method('acceptsLanguages')
.method('acceptsEncodings')
.method('acceptsCharsets')
.method('accepts')
.method('get')
.method('is')
.access('querystring')
.access('idempotent')
.access('socket')
.access('search')
.access('method')
.access('query')
.access('path')
.access('url')
.access('accept')
.getter('origin')
.getter('href')
.getter('subdomains')
.getter('protocol')
.getter('host')
.getter('hostname')
.getter('URL')
.getter('header')
.getter('headers')
.getter('secure')
.getter('stale')
.getter('fresh')
.getter('ips')
.getter('ip');