本系列文章是本人學習相關知識時所積累的筆記,以記錄自己的學習歷程,也爲了方便回顧知識;故文章內容較爲隨意簡練,抱着學習目的來的同學務必轉移他處,以免我誤人子弟~
delegate函數原理
Koa源碼中,是這麼使用delegate
/**
* 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');
實現的功能是將ctx.response和ctx.request的屬性代理到ctx上,即可以通過ctx.path訪問到ctx.request.path,可以通過ctx.body = someObj對ctx.response.body賦值someObj
看delegate源碼:
// delegate源碼
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 = [];
}
第一句的作用是這個函數可以當成構造函數來使用,也可以想普通函數一樣掉用,如果像普通函數調用,則觸發第一句代碼,最終仍然返回實例,所以Koa源碼的用法也可改爲:
let delegate = new delegate(proto,"response");
delegate
.access("body")
...
method方法:代理方法
// delegate源碼
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;
};
getter方法:代理屬性get行爲
// delegate源碼
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;
};
setter方法:代理屬性set行爲
// delegate源碼
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;
};
access方法:代理屬性get和set行爲
// delegate源碼
Delegator.prototype.access = function(name){
return this.getter(name).setter(name);
};
.__defineSetter__
和.__defineGetter__
現在已經快被廢棄,所以我們對於getter、setter和access方法可以進行如下改寫:
// getter
Delegator.prototype.getter = function(name){
var proto = this.proto;
var target = this.target;
this.getters.push(name);
Object.defineProperty(proto,name,{
get(){
return proto[target][name];
}
})
return this;
}
// setter
Delegator.prototype.setter = function(name){
var proto = this.proto;
var target = this.target;
this.setters.push(name);
Object.defineProperty(proto,name,{
set(value){
proto[target][name] = value;
}
})
return this;
}
// accsee
Delegator.prototype.access = function(name){
Object.defineProperty(proto,name,{
get(){
return proto[target][name];
},
set(value){
proto[target][name] = value;
},
})
return this;
}
delegate源碼中還有個fluent方法,koa中沒有用到
// delegate源碼
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;
};
作用跟access相近,但是改變了取值和賦值方式:
// access
ctx.body // 返回 ctx.response.body 的值
ctx.body = someObj // ctx.response.body 的值變爲 someObj
// fluent
ctx.body() // 返回 ctx.response.body 的值
ctx.body(someObj) // ctx.response.body 的值變爲 someObj