实现类的步骤javascript
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
是如何实现类的方法,有几个重要的问题须要搞清楚java
JS
是如何建立类的$super
,是如何作到在子类中共存的addMethods
往类中添加方法的下面来经过prototype.js
的class
来具体分析web
var Class = (function() { function subclass() {}; function create() { // ... } function addMethods(source) { // ... } // 暴露给外部的接口 return { create: create, Methods: { addMethods: addMethods } }; })();
内部实现其实很简单,Class
是一个当即执行函数,里面只有三个函数,并且subclass
仍是个空函数segmentfault
/* 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
面向对象系列app