John Resig 写了一篇关于 JavaScript 里 类似其它语言的 "继承", 灵感来自于 base2 and PrototypeJS. 他为文章起名为"Simple JavaScript Inheritance" . 他使用的一些很巧妙的技术来实现 类似于java 的 extend方法.
其实 Simple JavaScript Inheritance 的源码就那么20多行,咱们结合 http://ejohn.org/blog/simple-javascript-inheritance/ 上的demo给大家讲解一下
(function() {
var initializing = false,
fnTest = /xyz/.test(function() {
xyz;
}) ? /\b_super\b/ : /.*/;
this.Class = function() {}; //this---->window
Class.extend = function(prop) {
var _super = this.prototype; // this---->Person构造函数 this.prototype---->Person.prototype
initializing = true;
var prototype = new this(); //Person {}
initializing = false;
for(var name in prop) { //可以遍历到init dance swingSword
prototype[name] = //init方法里面调用了 _super
typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn) {
return function() {
var tmp = this._super;
this._super = _super[name]; //闭包的原理
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
function Class() {
if(!initializing && this.init)
this.init.apply(this, arguments);
}
Class.prototype = prototype;
Class.constructor = Class;
Class.extend = arguments.callee;
return Class;
};
})();
var Person = Class.extend({
init: function(isDancing) {
this.dancing = isDancing;
},
dance: function() {
return this.dancing;
}
});
var Ninja = Person.extend({
init: function() {
this._super(false);
},
dance: function() {
// Call the inherited version of dance()
return this._super();
},
swingSword: function() {
return true;
}
});
var p = new Person(true);
p.dance(); // => true
var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true
首先分析这父类的构造方法是怎么生成的
var Person = Class.extend({
init: function(isDancing) {
this.dancing = isDancing;
},
dance: function() {
return this.dancing;
}
});
我们就对执行上面面这段代码时进行debug分析
(function() {
var initializing = false,
fnTest = /xyz/.test(function() {
xyz;
}) ? /\b_super\b/ : /.*/;
this.Class = function() {}; //this---->window
Class.extend = function(prop) {
var _super = this.prototype; // this---->function(){} 即this===window.Class
initializing = true;
var prototype = new this(); //Class {}
initializing = false;
for(var name in prop) { //可以遍历到init dance
prototype[name] =
typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn) {
return function() {
var tmp = this._super;
this._super = _super[name];
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name]; //执行Person时,执行的都是 prototype[name]=prop[name],上面那个并没有执行到上面那个判断
}
function Class() {
if(!initializing && this.init)
this.init.apply(this, argum ents);
}
Class.prototype = prototype;
Class.constructor = Class;
Class.extend = arguments.callee;
return Class;
};
})();
执行完var Person = Class.extend ,会产生如下的继承原型链
分析子类的构造方法是怎么生成的
var Ninja = Person.extend({
init: function() {
this._super(false);
},
dance: function() {
// Call the inherited version of dance()
return this._super();
},
swingSword: function() {
return true;
}
});
对上述代码进行debug分析
(function() {
var initializing = false,
fnTest = /xyz/.test(function() {
xyz;
}) ? /\b_super\b/ : /.*/;
this.Class = function() {}; //this---->window
Class.extend = function(prop) {
var _super = this.prototype; // this---->Person构造函数 this.prototype---->Person.prototype
initializing = true;
var prototype = new this(); //Person {}
initializing = false;
for(var name in prop) { //可以遍历到init dance swingSword
prototype[name] = //init方法里面调用了 _super
typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn) {
return function() {
var tmp = this._super;
this._super = _super[name]; //闭包的原理
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
function Class() {
if(!initializing && this.init)
this.init.apply(this, arguments);
}
Class.prototype = prototype;
Class.constructor = Class;
Class.extend = arguments.callee;
return Class;
};
})();
要分析上面这个继承语句究竟进行了那些操作关键是搞明白
Typeofprop[name]=="function"&&typeof_super[name]=="function"&&fnTest.test(prop[name])
这行语句究竟判断了些什么
Typeofprop[name]=="function" prop里面的[name]属性要是方法
typeof_super[name]=="function" 父对象里面要要一个name也是[name]的属性
fnTest.test(prop[name]) prop里面的[name]方法有没有调用 _super
fnTest=/xyz/.test(function() {
xyz;
})?/\b_super\b/ : /.*/;
这个fnTest的目的就是为了验证 [name]method中是否使用了 "_super()"调用,
/xyz/.test(function() {xyz; })是为了测试浏览器是否支持" function decompilation(函数反编译)", Function serialisation 是在一个函数被转换成字符串时发生的. 现在很多浏览器都支持 toString 方法。如果一个浏览器支持Function serialization,那么在进行/xyz/.test(function() {xyz; }) 的时候会把function() {xyz; } toString成字符串“function() {xyz; }”,这时候/xyz/.test(function() {xyz; })自然就会返回true。
如果浏览器支持函数反编译就用/\b_super\b/ 匹配,否则就用/.*/ 匹配,这会始终返回 true, 那么会始终对_super 进行额外的操作, 导致这些新的方法不能在 _super 中使用.这会有一些小的性能消耗.但能保证在所有浏览器中 正常执行.
最终 执行完var Ninja = Person.extend ,会产生如下的继承原型链