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

前面引见了prototype.jsMootools.js是怎样完成类,及其类的属性和作用的。本日引见的klass.js就是纯真的完成面向对象的库,只要90多行,也按例剖析吧。

完成类的步骤

  • 第一步是运用klass新建类,初始化的牢固函数是initialize,不能运用别的称号
  • 子类运用ParentClassName.extend{// 子类要领}继续
  • 子类中与父类的同名要领,假如须要在父类的同名要领上拓展,须要在子类的要领体中运用this.supr(args)
  • 假如须要在类的表面增添要领,能够运用methods要领
// 运用 klass 建立类
    var Person = klass({
        // 初始函数牢固为 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)
        }
    });

    // 运用 methods 给类增加要领,子类能够继续该要领
    Person.methods({
        getAge:function(age){
            console.log("My age is " + age);
        }
    })

    // 子类直接经由过程 ParentClassName.extend 来继续父类
    var Chinese = Person.extend({
        initialize:function(name, addr){
            // 运用 this.supr(args)来运用父类的同名函数
            this.supr(name);
            this.addr = addr;
        },
        getAddr:function(){
            console.log("My address is " + this.addr);
        }
    });

    // 子类直接经由过程 ParentClassName.extend 来继续父类
    var Japanese = Person.extend({
        initialize:function(name){
            this.supr(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是怎样建立类的
  • 子类是怎样完成继续父类属性和要领的
  • 子类继续父类的属性,修改了以后,其他子类再次继续父类,父类的属性的值为什么不会转变
  • 子类和父类的同名函数,在同名函数中运用$supr,是怎样做到在子类中共存的
    怎样完成,不在类中,而是运用methods往类中增加要领的

下面来经由过程klass.js来具体剖析

!function (name, context, definition) {
  if (typeof define == 'function') define(definition)
  else if (typeof module != 'undefined') module.exports = definition()
  else context[name] = definition()
}('klass', this, function () {
  var context = this
    , f = 'function'
      // 是不是运用了 supr 来挪用父类的同名函数
    , fnTest = /xyz/.test(function () {xyz}) ? /\bsupr\b/ : /.*/
    , proto = 'prototype'

    // o 为建立类时,类的要领
  function klass(o) {
    return extend.call(isFn(o) ? o : function () {}, o, 1)
  }

  // 推断对象是不是是函数
  function isFn(o) {
    return typeof o === f
  }

  // 将父类的要领/属性,附加到子类中
  function wrap(k, fn, supr) {
    return function () {
      var tmp = this.supr
        // 当前函数的 supr,就是父类的同名函数
      this.supr = supr[proto][k]
      var undef = {}.fabricatedUndefined
      var ret = undef
      try {
        // this 是当前类,fn 是父类的函数,fn 的上下文是绑定在当前类中,所以就即是父类的要领就继续到子类中了
        ret = fn.apply(this, arguments)
      } finally {
        this.supr = tmp
      }
      return ret
    }
  }

  // 子类继续父类的属性,假如有同名函数,就运用 wrap 要领处置惩罚,假如没有,就完整继续该属性
  // what : child; o : parent; supr: parentClass
  function process(what, o, supr) {
    for (var k in o) {
      if (o.hasOwnProperty(k)) {
        what[k] = isFn(o[k])
          && isFn(supr[proto][k])
          && fnTest.test(o[k])
          ? wrap(k, o[k], supr) : o[k]
      }
    }
  }

  // 完成继续的主函数, o建立类时的一切函数,fromSub 为1,不明白为什么不把fromSub设置为true/false
  function extend(o, fromSub) {
    // must redefine noop each time so it doesn't inherit from previous arbitrary classes
    function noop() {}
    noop[proto] = this[proto]
    var supr = this
      , prototype = new noop()
      , isFunction = isFn(o)
      , _constructor = isFunction ? o : this
      , _methods = isFunction ? {} : o
    function fn() {
      // 假如当前类设置类 initialize 函数,就把传给当前类的参数传递给该函数
      if (this.initialize) this.initialize.apply(this, arguments)
      else {
        // 假如没有设置 initialize ,传入类的参数也能被别的函数运用
        fromSub || isFunction && supr.apply(this, arguments)
        _constructor.apply(this, arguments)
      }
    }

    // 运用 methods 增加要领到当前类,o 为运用 methods 内的要领
    fn.methods = function (o) {
      process(prototype, o, supr)
      fn[proto] = prototype
      return this
    }

    // 指定 fn 的 constructor
    fn.methods.call(fn, _methods).prototype.constructor = fn

    // 运用 ParentClassName.extend 来完成继续时刻的
    fn.extend = arguments.callee
      // 运用 implement 来重写父类的要领或许拓展父类的要领
      // o : 函数名 ; optFn : 函数
    fn[proto].implement = fn.statics = function (o, optFn) {
      o = typeof o == 'string' ? (function () {
        var obj = {}
        obj[o] = optFn
        return obj
      }()) : o
      // 运用 process 把 implement 中的函数增加到当前类中
      process(this, o, supr)
      return this
    }

    return fn
  }

  return klass
});

JS面向对象系列

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