Koa源碼:delegate模塊

本系列文章是本人學習相關知識時所積累的筆記,以記錄自己的學習歷程,也爲了方便回顧知識;故文章內容較爲隨意簡練,抱着學習目的來的同學務必轉移他處,以免我誤人子弟~

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章