• 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;
    };
  • 相关阅读:
    Attributes.Add用途与用法
    Reapter控件中更换Td背景色
    SQL SERVER查询时间条件式写法
    C# Cache何时使用及使用方法
    C#中Cache用法
    用sql语句将两个时间相减,得到时间距的DateDiff()函数
    HTML5 带进度条的异步文件上传原理
    Node环境Grunt开发流
    HTML5的Web SQL Databases(html5 本地数据库)API
    移动端范围拖动选择效果
  • 原文地址:https://www.cnblogs.com/tugenhua0707/p/10562378.html
Copyright © 2020-2023  润新知