Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[javaScript] delegates源码解读 #28

Open
zgfang1993 opened this issue Nov 17, 2018 · 0 comments
Open

[javaScript] delegates源码解读 #28

zgfang1993 opened this issue Nov 17, 2018 · 0 comments

Comments

@zgfang1993
Copy link
Owner

  • 基本用法
  • 源码解读

基本用法:

将内部对象的变量或者函数绑定在暴露在外层的变量上,直接通过 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');

参考:https://juejin.im/post/5b9339136fb9a05d3634ba13

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant