javascript是一门弱类型的语言,虽然是面向对象,但是没有类的概念。不过由于其强大的动态灵活性,我们可以模拟传统强类型语言的继承模式。
一、默认模式
最常用的的一种默认方法,prototype指向父类的一个对象。
function Person(){
this.name = 'zs';
}
Person.prototype.say = function(){
alert('hello');
}
function Child(){
}
Child.prototype = new Person();
console.log(new Child().name);// 结果 zs
此模式会继承this和原型里面所有的属性,子类同名属性,会隐藏父类的。
缺点:this属性是访问原型获得的,并不是子类的自身属性,子类修改,则父类也会改变
二、借用模式
call、apply方法借用父类的构造函数,子类将有this属性副本,修改不会影响父类
function Person(){
this.name = 'zs';
}
Person.prototype.say = function(){
console.log('hello');
}
function Child(){
//借用父类构造函数,子类拥有属性副本
Person.apply(this,arguments);
}
console.log(new Child().name);// 结果 zs
new Child().say();// 结果 undefind
但此模式只能继承this属性,不能继承原型方法
三、借用模式+默认模式
function Person(){
this.name = 'zs';
}
Person.prototype.say = function(){
console.log('hello');
}
function Child(){
//借用父类构造函数,子类拥有属性副本
Person.apply(this,arguments);
}
Child.prototype = new Person();
console.log(new Child().name);// 结果 zs
new Child().say();// 结果 hello
此模式拥有属性副本,并继承原型中的属性
缺点:有2套this属性,效率底下
四、共享原型模式
prototype指向父类原型
function Person(){
this.name = 'zs';
}
Person.prototype.say = function(){
console.log('hello');
}
function Child(){
}
Child.prototype = Person.prototype;
console.log(new Child().name);// undefined
new Child().say();// 结果 hello
此模式子类和父类永享原型,只继承原型属性,不包括this属性
缺点:平级,子类修改原型,父类也会修改
五、临时构造函数模式(利用了原型继承的思想,下一篇博客会讲)
function Person(){
this.name = 'zs';
}
Person.prototype.say = function(){
console.log('hello');
}
function Child(){
}
function f(){
}
f.prototype = Person.prototype;
Child.prototype = new f();
console.log(new Child().name);// 结果 undefined
new Child().say();// 结果 hellow
此模式改进了共享模式的缺点。用了一个临时函数f来共享原型。并让子类继承。子类修改只会修改f的对象并不会修改原型。实际上是为子类提供了一个原型。
只继承原型属性。
注:临时构造函数模式 圣杯版(推荐)
var inherit = function(){
var fun = function(){}
return function(c,p){
fun.prototype = p.prototype;
c.prototype = new fun();
c.father = p.prototype;
c.prototype.constructor = c;
}
}()
六、kclass 语法糖(完美模拟类式继承)
借用模式继承this属性
临时构造函数模式继承原型属性
约定构造函数名称
返回一个新构造函数
var klass = function(Parent,props){
var child,F,i;
child = function(){
//先调父类构造函数,再调子类构造函数
if(child.father && child.father.hasOwnProperty("__construct")){
child.father.__construct.apply(this,arguments);
}
if(child.prototype.hasOwnProperty("__construct")){
child.prototype.__construct.apply(this,arguments);
}
}
//临时构造函数模式 继承
Parent = Parent || Object;
F = function(){};
F.prototype = Parent.prototype;
child.father = Parent.prototype;
child.prototype = new F();
child.prototype.constructor = child;
//添加实现方法
for(i in props){
if(props.hasOwnProperty(i)){
child.prototype[i] = props[i];
}
}
return child;
}
//测试
var Man = klass(null,{
__construct:function(what){
console.log(("Man's constructor'"));
this.name = what;
},
getName:function(){
return this.name;
}
})
var first = new Man('adam');
console.log(first.getName()); //结果 adam;
var SuperMan = klass(Man,{
__construct:function(what){
console.log(("SuperMan's constructor'"));
this.name = what;
},
getName:function(){
var name = SuperMan.father.getName.call(this);
return "I am"+name;
}
})
var clark = new SuperMan('clark kent');
console.log(clark.getName());//结果 i am clark kent