西西软件下载最安全的下载网站、值得信赖的软件下载站!

首页编程开发javascript|JQuery → javascript面向对象包装类Class的类库解析

javascript面向对象包装类Class的类库解析

相关软件相关文章发表评论 来源:pigtail时间:2013/1/22 14:42:29字体大小:A-A+

作者:穆乙点击:0次评论:0次标签: 面向对象

2 页 KLASS

二、KLASS

 项目地址:https://github.com/ded/klass

先看使用方法:

a、新建一个类

// 声明一个类
var Person = klass(function (name) {
  this.name = name
})
  .statics({//静态方法
    head: ':)',
    feet: '_|_'
  })
  .methods({//实例方法
    walk: function () {}
  })

b、继承一个类

// SuperHuman 继承 Person
var SuperHuman = Person.extend(function (name) {
  // 自动调用父类的构造方法
})
  .methods({
    walk: function() {
      // 显式声明调用父类的walk方法
      this.supr()
      this.fly()
    },

    fly: function() {}

  })

new SuperHuman('Zelda').walk()

c、字面量方式声明一个类

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、实现一个类的方法

因为有时候你可能希望覆写或者混合一个实例方法,可以这样:

// 可以传递一个字面量去继承
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的基本设计思路很明确,极力的模仿其它语言的继承方式。比如:子类构造方法调用父类的构造方法,还可以显式的声明调用父类的方法。

这种判断都是基于正则匹配:fnTest = /xyz/.test(function () {xyz;}) ? /\bsupr\b/ : /.*/;关键字"super"

如果显示的声明了要调用父类的方法,那么声明方法的时候,就包装成一个内部调用父类方法且返回相同值的函数,给当前类的方法。

另一方面,构造方法,也是比较灵活的。如果显示的声明了initialize,那么这就是构造方法。否则如果参数是个function那么它就做为构造方法,否则就用父类的构造方法。

通过statics方式添加静态方法,通过实例的implements和静态方法methods添加实例方法。

通过父类的extend实现继承。

同时,类库为commonJS和浏览环境都提供了支持!

/**
  * 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用来验证是否可能通过正则找出调用super父类方法的方法
  var fnTest = /xyz/.test(function () {xyz;}) ? /\bsupr\b/ : /.*/,
      noop = function (){},
      proto = 'prototype',
      isFn = function (o) {
        return typeof o === f;
      };
  // 基础类
  function klass(o) {
    return extend.call(typeof o == f ? o : noop, o, 1);
  }

  // 包装成一个借用super同名方法的函数
  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];
      // 借用执行并保存返回值
      var ret = fn.apply(this, arguments);
      // 恢复原this.super
      this.supr = tmp;
      // 返回返回值,保证wrap后的返回值跟原来一致
      return ret;
    };
  }
   // 如果o和super有同名方法,且o显式声明借用super的同名方法,就wrap成一个待执行函数供使用
   // 如果没有显式的声明借用super的同名方法,或者是o独有的方法,或者不是方法就直接用
  function process(what, o, supr) {
    for (var k in o) {
      // 如果是非继承方法,按方法注释规则执行,最终都放进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];
      }
    }
  }
  // 继承方法的实现,fromSub是用来控制是否继承而来,上面的klass里面fromSub是1,表明非继承而来,构造函数不借用super执行
  function extend(o, fromSub) {
    // noop做为媒介类实现原型继承的解除引用
    noop[proto] = this[proto];
    
    var supr = this,
        prototype = new noop(), // 创建实例对象供原型继承使用,解除引用
        isFunction = typeof o == f,
        _constructor = isFunction ? o : this,// 如果o是一个构造方法就用,否则由this来决定构造函数
        _methods = isFunction ? {} : o,    // 如果o是一个{...}应该用methods放到fn原型里,如果里面有initialize就是构造函数,如果o是函数就由上面_constructor决定o是构造函数
        fn = function () { // 因为kclass借助了kclass,所以最终实际上返回的就是fn,fn其实就新类的构造函数
          
          //1 如果o是{...}就会被methods直接过滤并添加到fn的原型里,如果o里面有initialize,那么fn的原型里就有initialize,那么它就是构造方法
          //2 如果o是function,methods什么也添加不到fn的原型里,但是_constructor会接受o当构造函数
          //3 如果o是{....},同时里面也没有initialize,那么就是this当构造函数,如果在klass里由call决定,显然构造函数是noop,如果在非基础类里,构造函数就是父类的构造函数
          //  由于o不是函数不会自动调用父类的构造函数,只是把父类的构造函数当做当前类的构造函数----这都是由于this的指向决定的
          console.log(this);
          if (this.initialize) {
            this.initialize.apply(this, arguments);
          } else {
            // 调用父类构造方法
            // 如上面3,o不是函数,不会调用父类的构造方法
            // 基础类无父类,不会调用父类构造方法
            fromSub || isFn(o) && supr.apply(this, arguments);
            // 调用本类构造方法
            // 参考上面2,3要么是noop要么是o
            console.log(_constructor==noop);
            _constructor.apply(this, arguments);
          }
        };
    // 构造原型方法的接口
    fn.methods = function (o) {
      process(prototype, o, supr);
      fn[proto] = prototype;
      return this;
    };
    // 执行实现新类原型,保证新类的constructor
    fn.methods.call(fn, _methods).prototype.constructor = fn;
    // 保证新类可以被继承
    fn.extend = arguments.callee;
    // 添加实例方法或者静态方法,statics:静态方法,implement实例方法
    fn[proto].implement = fn.statics = function (o, optFn) {
      // 保证o是一个object对象,如果o是一个字符串,那么就是添一个方法的情况,如果o是一个object对象说明是批量添加的
      // 因为要从o里面拷贝
      o = typeof o == 'string' ? (function () {
        var obj = {};
        obj[o] = optFn;
        return obj;
      }()) : o;
      // 添加实例方法或者静态方法,statics:静态方法,implement实例方法
      process(this, o, supr);
      return this;
    };

    return fn;
  }

  // 后台用,nodejs
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = klass;
  } else {
    
    var old = context.klass;
    // 防冲突
    klass.noConflict = function () {
      context.klass = old;
      return this;
    };
    // 前台浏览器用
    //window.kclass = kclass;
    context.klass = klass;
  }

}(this, 'function');
              
              

        

    相关评论

    阅读本文后您有什么感想? 已有人给出评价!

    • 8 喜欢喜欢
    • 3 顶
    • 1 难过难过
    • 5 囧
    • 3 围观围观
    • 2 无聊无聊

    热门评论

    最新评论

    发表评论 查看所有评论(0)

    昵称:
    表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲
    字数: 0/500 (您的评论需要经过审核才能显示)
    推荐文章

    没有数据