prototype.js 是怎样完成JS的类以及类的相干属性和作用

完成类的步骤

  • 第一步是运用Class.create新建类,初始化的牢固函数是initialize,不能运用别的称号
  • 子类也是运用Class.create新建,父类放在第一个参数中,如var Cat = Class.create(Animal,{});
  • 子类中与父类的同名要领,假如须要在父类的同名要领上拓展,在须要在第一个参数中运用$super,然后在要领体内运用$super(args);
  • 假如须要在类的表面增添要领,能够运用addMethods要领
// 运用 Class.create 建立类
    var Person = Class.create({
        // 初始函数牢固为 initialize, 假如不设置,会默许建立一个空函数给 initialize
        initialize:function(name) {
            this.name = name;
            this.friends = ['jack', 'mark'];
        },
        getName: function(){
            console.log("My name is " + this.name);
        },
        setFriends:function(friend){
            this.friends.push(friend);
        },
        getFriends:function(){
            console.log(this.friends)
        }
    });

    // 运用 addMethods 给在类的初始构建以外增加要领,子类能够继续该要领
    Person.addMethods({
        getAge:function(age){
            console.log("My age is " + age);
        }
    })

    // 子类经由过程 Class.create 建立类,第一个参数为父类的名字
    var Chinese = Class.create(Person,{
        // 运用 $super 为第一个参数,示意当前函数在父类的同名函数上拓展
        initialize:function($super, name, addr){
            $super(name);
            this.addr = addr;
        },
        getAddr:function(){
            console.log("My address is " + this.addr);
        }
    });

    var Japanese = Class.create(Person, {
        initialize:function($super, name){
            $super(name);
        }
    })

    // 实例化类
    var men = new Chinese('allen', 'BeiJing');
    men.getName(); // My name is allen
    men.getAge(23); // My age is 23
    men.getAddr(); // My address is BeiJing

    // 以下考证 - 子类继续父类的属性,修正了以后,其他子类再次继续父类,父类的属性的值为什么不会转变
    var allen = new Person();
    allen.getFriends(); // ["jack", "mark"]

    var women = new Japanese();
    women.setFriends("lisa");
    women.getFriends(); // ["jack", "mark", "lisa"]

    var men = new Chinese();
    men.setFriends('peter');
    men.getFriends(); //["jack", "mark", "peter"]

    var wallen = new Person();
    wallen.getFriends(); //["jack", "mark"]

JS是怎样完成类的要领,有几个主要的题目须要搞清楚

  • JS是怎样建立类的
  • 子类是怎样完成继续父类属性和要领的
  • 子类继续父类的属性,修正了以后,其他子类再次继续父类,父类的属性的值为什么不会转变
  • 子类和父类的同名函数,在同名函数中运用$super,是怎样做到在子类中共存的
  • 怎样完成,不在类中,而是运用addMethods往类中增加要领的

下面来经由过程prototype.jsclass来具体分析

var Class = (function() {

  function subclass() {};
  function create() {
    // ... 
  }

  function addMethods(source) {
    // ...
  }

  // 暴露给外部的接口
  return {
    create: create,
    Methods: {
      addMethods: addMethods
    }
  };
})();

内部完成实在很简单,Class是一个马上实行函数,内里只要三个函数,而且subclass照样个空函数

/* Based on Alex Arnell's inheritance implementation. */

/**
 *  Refer to Prototype's web site for a [tutorial on classes and
 *  inheritance](http://prototypejs.org/learn/class-inheritance).
**/
var Class = (function() {

  function subclass() {};
  function create() {
    // $A 函数就是把参数转化成数组
    var parent = null, properties = $A(arguments);
    // 假如第一个参数是函数,就把他看成父类
    if (Object.isFunction(properties[0]))
      parent = properties.shift();

    function klass() {
      // klass 是新建的类,把传入的参数都绑定到 klass 的 initialize 要领中
      this.initialize.apply(this, arguments);
    }

    // 把经由过程 extend 要领,把 Class.Methods 的要领增加到 klass 中
    Object.extend(klass, Class.Methods);
    // 这里有指定 klass 的父类是哪个
    klass.superclass = parent;
    klass.subclasses = [];

    if (parent) {
      // 这里经由过程把父类的原型要领,都继续到当前类中
      // 经由过程中心变量 subclass 来通报 prototype 来防备因为子类的修正而致使父类的属性或许要领也被修正
      subclass.prototype = parent.prototype;
      // 每次子类都邑建立一个新的中心变量来通报,所以不管子类怎样修正属性,都不会影响到父类
      klass.prototype = new subclass;
      // 把当前类增加到父类的子类中
      parent.subclasses.push(klass);
    }

    for (var i = 0, length = properties.length; i < length; i++)
      // 前面把 addMethods 要领增加到 klass 中,这里就能够运用 addMethods 把传入参数中的要领,增加到 klass 中了
      klass.addMethods(properties[i]);

    // 假如 klass 没有初始化函数,就设置一个空函数
    if (!klass.prototype.initialize)
      klass.prototype.initialize = Prototype.emptyFunction;

    // 把 klass 的组织函数指向本身
    klass.prototype.constructor = klass;
    return klass;
  }

  
  // source 是一切要增加进来要领的鸠合
  function addMethods(source) {
    var ancestor   = this.superclass && this.superclass.prototype,
        properties = Object.keys(source);

    for (var i = 0, length = properties.length; i < length; i++) {
      // value 就是单个的要领
      var property = properties[i], value = source[property];
      // 假如参数中的第一个参数是 $super,就须要把父类的同名要领,通报进来
      if (ancestor && Object.isFunction(value) &&
          value.argumentNames()[0] == "$super") {
        // 把最初的 value 运用 method 存起来
        var method = value;
        // 继续父类的同名要领,然后把当前参数传进去
        value = (function(m) {
          return function() { return ancestor[m].apply(this, arguments); };
        })(property).wrap(method);
          // wrap 是把父类的同名要领,增加当前类的同名要领中

        // We used to use `bind` to ensure that `toString` and `valueOf`
        // methods were called in the proper context, but now that we're
        // relying on native bind and/or an existing polyfill, we can't rely
        // on the nuanced behavior of whatever `bind` implementation is on
        // the page.
        //
        // MDC's polyfill, for instance, doesn't like binding functions that
        // haven't got a `prototype` property defined.
        // 将 valueOf 的要领绑定到 method 中
        value.valueOf = (function(method) {
          return function() { return method.valueOf.call(method); };
        })(method);

          // 将 toString 的要领绑定到 method 中
        value.toString = (function(method) {
          return function() { return method.toString.call(method); };
        })(method);
      }
      this.prototype[property] = value;
    }

    return this;
  }

  // 暴露给外部的接口
  return {
    create: create,
    Methods: {
      addMethods: addMethods
    }
  };
})();

上面运用到的wrap函数,摘抄在下面

function wrap(wrapper) {
    var __method = this;
    return function() {
      var a = update([__method.bind(this)], arguments);
      return wrapper.apply(this, a);
    }
  }

// 这里就是把 args 中的属性,都增加到 array 中
function update(array, args) {
    var arrayLength = array.length, length = args.length;
    while (length--) array[arrayLength + length] = args[length];
    return array;
  }

JS面向对象系列

    原文作者:catchonme
    原文地址: https://segmentfault.com/a/1190000010430690
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞