koa2--delegates模块源码解读

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;
};

原文地址:https://www.cnblogs.com/tugenhua0707/p/10562378.html

时间: 2024-11-09 15:16:49

koa2--delegates模块源码解读的相关文章

分布式事务中间件 Fescar—RM 模块源码解读

前言在SOA.微服务架构流行的年代,许多复杂业务上需要支持多资源占用场景,而在分布式系统中因为某个资源不足而导致其它资源占用回滚的系统设计一直是个难点.我所在的团队也遇到了这个问题,为解决这个问题上,团队采用的是阿里开源的分布式中间件Fescar的解决方案,并详细了解了Fescar内部的工作原理,解决在使用Fescar中间件过程中的一些疑虑的地方,也为后续团队在继续使用该中间件奠定理论基础. 目前分布式事务解决方案基本是围绕两阶段提交模式来设计的,按对业务是有侵入分为:对业务无侵入的基于XA协议

koa源码解读

koa是有express原班人马打造的基于node.js的下一代web开发框架.koa 1.0使用generator实现异步,相比于回调简单和优雅和不少.koa团队并没有止步于koa 1.0, 随着node.js开始支持async/await,他们又马不停蹄的发布了koa 2.0,koa2完全使用Promise并配合async/await来实现异步,使得异步操作更臻完美. 一.快速开始 koa使用起来非常简单,安装好node.js后执行以下命令安装koa: npm init npm instal

vue源码解读预热-0

vueJS的源码解读 vue源码总共包含约一万行代码量(包括注释)特别感谢作者Evan You开放的源代码,访问地址为Github 代码整体介绍与函数介绍预览 代码模块分析 代码整体思路 总体的分析 从图片中可以看出的为采用IIFE(Immediately-Invoked Function Expression)立即执行的函数表达式的形式进行的代码的编写 常见的几种插件方式: (function(,){}(,))或(function(,){})(,)或!function(){}()等等,其中必有

线程本地变量ThreadLocal源码解读

  一.ThreadLocal基础知识   原始线程现状: 按照传统经验,如果某个对象是非线程安全的,在多线程环境下,对对象的访问必须采用synchronized进行线程同步.但是Spring中的各种模板类并未采用线程同步机制,因为线程同步会影响并发性和系统性能,而且实现难度也不小. ThreadLocal在Spring中发挥着重要的作用.在管理request作用域的bean,事务管理,任务调度,AOP等模块中都出现了它的身影. ThreadLocal介绍: 它不是一个线程,而是线程的一个本地化

Apache Beam WordCount编程实战及源码解读

概述:Apache Beam WordCount编程实战及源码解读,并通过intellij IDEA和terminal两种方式调试运行WordCount程序,Apache Beam对大数据的批处理和流处理,提供一套先进的统一的编程模型,并可以运行大数据处理引擎上.完整项目Github源码 负责公司大数据处理相关架构,但是具有多样性,极大的增加了开发成本,急需统一编程处理,Apache Beam,一处编程,处处运行,故将折腾成果分享出来. 1.Apache Beam编程实战–前言,Apache B

SpringMVC源码解读 - HandlerMapping

SpringMVC在请求到handler处理器的分发这步是通过HandlerMapping模块解决的.handlerMapping 还处理拦截器. 先看看HandlerMapping的继承树吧 可以大致这样做个分类: 1. 一个接口HandlerMapping,定义一个api: HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; 2. 一个基础抽象类:主要是准备上下文环境,提供getHand

AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilityManager

做ios开发,AFNetworking 这个网络框架肯定都非常熟悉,也许我们平时只使用了它的部分功能,而且我们对它的实现原理并不是很清楚,就好像总是有一团迷雾在眼前一样. 接下来我们就非常详细的来读一读这个框架的代码,我们的目标就是理解了它的思想之后,能够明白我们的请求是如何实现的,我们的代码哪里还需要进行改进,如果能够更进一步,我们能够总结出一套适合大部分应用的网络架构思想. 能够让一些人从中受益. 我们先来看看整个框架的文件系统,我们先不对每个文件的作用进行说明,在整个源码解读最后的一篇中我

AfNetworking 3.0源码解读

做ios开发,AFNetworking 这个网络框架肯定都非常熟悉,也许我们平时只使用了它的部分功能,而且我们对它的实现原理并不是很清楚,就好像总是有一团迷雾在眼前一样. 接下来我们就非常详细的来读一读这个框架的代码,我们的目标就是理解了它的思想之后,能够明白我们的请求是如何实现的,我们的代码哪里还需要进行改进,如果能够更进一步,我们能够总结出一套适合大部分应用的网络架构思想. 能够让一些人从中受益. 我们先来看看整个框架的文件系统,我们先不对每个文件的作用进行说明,在整个源码解读最后的一篇中我

RequireJs 源码解读及思考

写在前面: 最近做的一个项目,用的require和backbone,对两者的使用已经很熟悉了,但是一直都有好奇他们怎么实现的,一直寻思着读读源码.现在项目结束,终于有机会好好研究一下. 本文重要解读requirejs的源码,backbone源码分析将会随后给出. 行文思路: requirejs 基本介绍 requirejs使用后的几个好奇 requirejs源码解读 requirejs基本介绍 由于篇幅有限,这里不会详解requirejs的使用和api,建议读者朋友自己去用几次,再详读api.