学习
以下学习需要面向对象基础知识和prototype继承了解
什么是继承
ClassJs提供了完整的继承机制。
为什么要继承
因为父类的功能是不完善的,随着项目的迭代,性能功能上明显不足。
这个时候多个项目栏目可能依赖这个父类,导致你不能修改。
即使修改也会导致项目错乱,一改全部都改。
所以这个时候为了能达到效率和灵活,我们需要用面向对象继承机制。
父类是不完善的,子类通过继承父类的所有,并对不足的予以修订。
所以继承的任务有两个
1. 子类获取父类所有功能
2. 子类对父类不足的进行修改
继承还有两个特性即单根性和传递性
1. 单根性 (子类只有一个父类)
2. 传递性 (即子类可以作为父类不断传递下去)
教程
|
|
首先用Class.extend创建基类Person并传入prototype
因为js没有纯正的面向对象机制,所谓的继承是由prototype来实现。
当执行完Class.extend并传入prototype会返回一个构造函数给Person。这个函数的构造体是我们的Class的构造函数,prototype是我们传入的值。所以返回的构造函数,打印出来会是这样。
|
|
当我们运行
把true传入Person那么初始化函数init自动执行,dance所指向的就变成true。
这个时候用dance打印当前域的dance就变成了true
这个时候我们运行
用于继承Person这个类
这里的init里面的this._super(false)指向的是父类也就是Person内原型里面的init。
子类init和父类init是重名 ,这个时候子类会把对父类传递值得修改,传给父级。即等于
this._super( false ) == (this.dancing = false; )
dance同理
swingSword因为父类没有,所以它来源于自己,直接添加到prototype。
所以运行后的Ninja的构造函数是
|
|
这个时候运行
发现我们的dance变成false 是因为我们修改了原来的类,同时添加了swingSword扩充了父类。
从而实现了继承的特性。
代码分析
ClassJs用于对象的继承,源代码比较小巧90行左右,非常精简。
fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
test是为了判断字符串是否匹配。所以大部分浏览器对函数内部的数据如果是函数会执行toString保证运行。
例如1234567891011var a = {}undefined/a/.test(a)false/a/.test('a')true/a/.test(function(){a})truefnTest这里的目的就是为了判断当前浏览器是否支持函数toString,如果支持返回/\b_super\b/,否则返回 /.*/
首先都在(function(){})()这个自执行里面,防止对全局污染。
然后用 this.Class = function() {};创建构造函数Class.这里的this.Class的this是指向的window
然后是在Class类上添加extend方法,该方法用于实现继承,传入一个prop对象,返回Class的原型+prop对象。下面对Class.extend里面代码分析
- var _super = this.prototype; 这里 _super就是Class的原型。用于保存原型。
- 123initializing = true;var prototype = new this();initializing = false;
这三段用于初始化,把实例化的Class赋值给prototype
这是一段for循环用于把prop的属性复制给prototype
12345678910111213141516171819202122for (var name in prop) {// Check if we're overwriting an existing functionprototype[name] = typeof prop[name] == "function" &&typeof _super[name] == "function" && fnTest.test(prop[name]) ?(function(name, fn) {return function() {var tmp = this._super;// Add a new ._super() method that is the same method// but on the super-classthis._super = _super[name];// The method only need to be bound temporarily, so we// remove it when we're done executingvar ret = fn.apply(this, arguments);this._super = tmp;return ret;};})(name, prop[name]) :prop[name];}
我们分析下这一段
prototype[name] = typeof prop[name] == “function” && typeof _super[name] == “function” && fnTest.test(prop[name]) ? (function(name, fn){})(name, prop[name]):prop[name]
1. typeof prop[name] == "function" && typeof _super[name] == "function" 用于构造函数中的相应name是不是函数,传递过来的prop中的name是不是也是函数。
2. fnTest.test(prop[name]) 同样也是用于判断传来的prop是否有_super。
3. 如果上面两个都是true那么就把
|
|
|
|