前面介绍了prototype.js
和Mootools.js
是如何实现类,及其类的属性和做用的。今天介绍的klass.js
就是单纯的实现面向对象的库,只有90多行,也照例分析吧。javascript
实现类的步骤java
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是如何实现类的方法,有几个重要的问题须要搞清楚segmentfault
$supr
,是如何作到在子类中共存的methods
往类中添加方法的下面来经过klass.js
来具体分析app
!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
面向对象系列函数