西西軟件下載最安全的下載網(wǎng)站、值得信賴的軟件下載站!

首頁編程開發(fā)javascript|JQuery → javascript面向?qū)ο蟀b類Class的類庫解析

javascript面向?qū)ο蟀b類Class的類庫解析

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來源:pigtail時(shí)間:2013/1/22 14:42:29字體大小:A-A+

作者:穆乙點(diǎn)擊:0次評(píng)論:0次標(biāo)簽: 面向?qū)ο?/a>

2 頁 KLASS

二、KLASS

 項(xiàng)目地址:https://github.com/ded/klass

先看使用方法:

a、新建一個(gè)類

// 聲明一個(gè)類
var Person = klass(function (name) {
  this.name = name
})
  .statics({//靜態(tài)方法
    head: ':)',
    feet: '_|_'
  })
  .methods({//實(shí)例方法
    walk: function () {}
  })

b、繼承一個(gè)類

// SuperHuman 繼承 Person
var SuperHuman = Person.extend(function (name) {
  // 自動(dòng)調(diào)用父類的構(gòu)造方法
})
  .methods({
    walk: function() {
      // 顯式聲明調(diào)用父類的walk方法
      this.supr()
      this.fly()
    },

    fly: function() {}

  })

new SuperHuman('Zelda').walk()

c、字面量方式聲明一個(gè)類

var Foo = klass({
  foo: 0,
  initialize: function() {
    this.foo = 1
  },
  getFoo: function () {
    return this.foo
  },
  setFoo: function (x) {
    this.foo = x
    return this.getFoo()
  }
})

d、實(shí)現(xiàn)一個(gè)類的方法

因?yàn)橛袝r(shí)候你可能希望覆寫或者混合一個(gè)實(shí)例方法,可以這樣:

// 可以傳遞一個(gè)字面量去繼承
var Alien = SuperHuman.extend({
  beam: function() {
    this.supr()
    // beam into space
  }
})

var Spazoid = new Alien('Zoopo')

if (beamIsDown) {
  // 覆寫beam方法
  Spazoid.implement({
    beam: function() {
      this.supr()
      // fallback to jets
      this.jets()
    }
  })
}

下面看一下klass源代碼解析:

klass的基本設(shè)計(jì)思路很明確,極力的模仿其它語言的繼承方式。比如:子類構(gòu)造方法調(diào)用父類的構(gòu)造方法,還可以顯式的聲明調(diào)用父類的方法。

這種判斷都是基于正則匹配:fnTest = /xyz/.test(function () {xyz;}) ? /\bsupr\b/ : /.*/;關(guān)鍵字"super"

如果顯示的聲明了要調(diào)用父類的方法,那么聲明方法的時(shí)候,就包裝成一個(gè)內(nèi)部調(diào)用父類方法且返回相同值的函數(shù),給當(dāng)前類的方法。

另一方面,構(gòu)造方法,也是比較靈活的。如果顯示的聲明了initialize,那么這就是構(gòu)造方法。否則如果參數(shù)是個(gè)function那么它就做為構(gòu)造方法,否則就用父類的構(gòu)造方法。

通過statics方式添加靜態(tài)方法,通過實(shí)例的implements和靜態(tài)方法methods添加實(shí)例方法。

通過父類的extend實(shí)現(xiàn)繼承。

同時(shí),類庫為commonJS和瀏覽環(huán)境都提供了支持!

/**
  * Klass.js - copyright @dedfat
  * version 1.0
  * https://github.com/ded/klass
  * Follow our software http://twitter.com/dedfat :)
  * MIT License
  */
!function (context, f) {
  // fnTest用來驗(yàn)證是否可能通過正則找出調(diào)用super父類方法的方法
  var fnTest = /xyz/.test(function () {xyz;}) ? /\bsupr\b/ : /.*/,
      noop = function (){},
      proto = 'prototype',
      isFn = function (o) {
        return typeof o === f;
      };
  // 基礎(chǔ)類
  function klass(o) {
    return extend.call(typeof o == f ? o : noop, o, 1);
  }

  // 包裝成一個(gè)借用super同名方法的函數(shù)
  function wrap(k, fn, supr) {
    return function () {
      // 緩存原this.super
      var tmp = this.supr;
      // 暫把this.super改造成借用super的同名方法above
      // 供o里顯式的聲明(fnTest.text(fn)==true)要借用super的同名方法使用
      this.supr = supr[proto][k];
      // 借用執(zhí)行并保存返回值
      var ret = fn.apply(this, arguments);
      // 恢復(fù)原this.super
      this.supr = tmp;
      // 返回返回值,保證wrap后的返回值跟原來一致
      return ret;
    };
  }
   // 如果o和super有同名方法,且o顯式聲明借用super的同名方法,就wrap成一個(gè)待執(zhí)行函數(shù)供使用
   // 如果沒有顯式的聲明借用super的同名方法,或者是o獨(dú)有的方法,或者不是方法就直接用
  function process(what, o, supr) {
    for (var k in o) {
      // 如果是非繼承方法,按方法注釋規(guī)則執(zhí)行,最終都放進(jìn)what
      if (o.hasOwnProperty(k)) {
        what[k] = typeof o[k] == f
          && typeof supr[proto][k] == f
          && fnTest.test(o[k])
          ? wrap(k, o[k], supr) : o[k];
      }
    }
  }
  // 繼承方法的實(shí)現(xiàn),fromSub是用來控制是否繼承而來,上面的klass里面fromSub是1,表明非繼承而來,構(gòu)造函數(shù)不借用super執(zhí)行
  function extend(o, fromSub) {
    // noop做為媒介類實(shí)現(xiàn)原型繼承的解除引用
    noop[proto] = this[proto];
    
    var supr = this,
        prototype = new noop(), // 創(chuàng)建實(shí)例對(duì)象供原型繼承使用,解除引用
        isFunction = typeof o == f,
        _constructor = isFunction ? o : this,// 如果o是一個(gè)構(gòu)造方法就用,否則由this來決定構(gòu)造函數(shù)
        _methods = isFunction ? {} : o,    // 如果o是一個(gè){...}應(yīng)該用methods放到fn原型里,如果里面有initialize就是構(gòu)造函數(shù),如果o是函數(shù)就由上面_constructor決定o是構(gòu)造函數(shù)
        fn = function () { // 因?yàn)閗class借助了kclass,所以最終實(shí)際上返回的就是fn,fn其實(shí)就新類的構(gòu)造函數(shù)
          
          //1 如果o是{...}就會(huì)被methods直接過濾并添加到fn的原型里,如果o里面有initialize,那么fn的原型里就有initialize,那么它就是構(gòu)造方法
          //2 如果o是function,methods什么也添加不到fn的原型里,但是_constructor會(huì)接受o當(dāng)構(gòu)造函數(shù)
          //3 如果o是{....},同時(shí)里面也沒有initialize,那么就是this當(dāng)構(gòu)造函數(shù),如果在klass里由call決定,顯然構(gòu)造函數(shù)是noop,如果在非基礎(chǔ)類里,構(gòu)造函數(shù)就是父類的構(gòu)造函數(shù)
          //  由于o不是函數(shù)不會(huì)自動(dòng)調(diào)用父類的構(gòu)造函數(shù),只是把父類的構(gòu)造函數(shù)當(dāng)做當(dāng)前類的構(gòu)造函數(shù)----這都是由于this的指向決定的
          console.log(this);
          if (this.initialize) {
            this.initialize.apply(this, arguments);
          } else {
            // 調(diào)用父類構(gòu)造方法
            // 如上面3,o不是函數(shù),不會(huì)調(diào)用父類的構(gòu)造方法
            // 基礎(chǔ)類無父類,不會(huì)調(diào)用父類構(gòu)造方法
            fromSub || isFn(o) && supr.apply(this, arguments);
            // 調(diào)用本類構(gòu)造方法
            // 參考上面2,3要么是noop要么是o
            console.log(_constructor==noop);
            _constructor.apply(this, arguments);
          }
        };
    // 構(gòu)造原型方法的接口
    fn.methods = function (o) {
      process(prototype, o, supr);
      fn[proto] = prototype;
      return this;
    };
    // 執(zhí)行實(shí)現(xiàn)新類原型,保證新類的constructor
    fn.methods.call(fn, _methods).prototype.constructor = fn;
    // 保證新類可以被繼承
    fn.extend = arguments.callee;
    // 添加實(shí)例方法或者靜態(tài)方法,statics:靜態(tài)方法,implement實(shí)例方法
    fn[proto].implement = fn.statics = function (o, optFn) {
      // 保證o是一個(gè)object對(duì)象,如果o是一個(gè)字符串,那么就是添一個(gè)方法的情況,如果o是一個(gè)object對(duì)象說明是批量添加的
      // 因?yàn)橐獜膐里面拷貝
      o = typeof o == 'string' ? (function () {
        var obj = {};
        obj[o] = optFn;
        return obj;
      }()) : o;
      // 添加實(shí)例方法或者靜態(tài)方法,statics:靜態(tài)方法,implement實(shí)例方法
      process(this, o, supr);
      return this;
    };

    return fn;
  }

  // 后臺(tái)用,nodejs
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = klass;
  } else {
    
    var old = context.klass;
    // 防沖突
    klass.noConflict = function () {
      context.klass = old;
      return this;
    };
    // 前臺(tái)瀏覽器用
    //window.kclass = kclass;
    context.klass = klass;
  }

}(this, 'function');
              
              

        
    推薦文章

    沒有數(shù)據(jù)