JS在意义上来说并没有真正的继承,它所支持的是实现继承,而且他的实现继承的主要方式是依靠原型链来完成的。
我们都知道每个对象都有一个[Prototype],这个所指向的是这个对象的构造函数的prototype,原型链继承就是将sub的原型对象 (sub.prototype = new super()) 等于super的实例,这样我们就可以通过原型链去找到super的属性和方法了~
function SuperType(){
this.name = "小白";
this.types = ["金毛","哈士奇"];
}
SuperType.prototype.sayName = function(){
return this.name;
};
function SubType(){
this.name = "大白"
}
//继承了SuperTyoe
SubType.prototype = new SuperType();
SubType.prototype.sayHost = function(){
return "白哥"
};
var dog = new SuperType();
var dog1 = new SubType();
var dog2 = new SubType();
dog2.name = "老白";
dog1.types.push('柯基');
console.log(dog1.sayName(),dog2.sayName());
console.log(dog1.types,dog2.types);
// 大白 老白
// ["金毛", "哈士奇", "柯基"] , ["金毛", "哈士奇", "柯基"]
1、所有的SubType.prototype都是一个SuperType的实例,这就造成了,SuperType内的引用类型会被所有的SubType实例共享,所以更改dog1.types会影响到dog2.types
2、还有一点就是不能在不影响所有sub对象实例的情况下向超类super构造函数传递参数
这是为了解决原型链继承方式的缺陷1说想出的办法,但是还是有缺陷的
function SuperType(name){
this.name = name;
this.types = ["金毛","哈士奇"];
}
SuperType.prototype.sayName = function(){
return this.name;
};
function SubType(name){
SuperType.call(this,name);
}
var dog1 = new SubType("白白");
var dog2 = new SubType("嘿嘿");
dog1.types.push("柯基");
console.log(dog1.types,dog2.types);
//这样是不行的,因为我们只是使用call方法,但是sub原型链并没有改变所以找不到super的sayName
console.log(dog2.sayName(),dog1.sayName())
// ["金毛", "哈士奇", "柯基"],["金毛", "哈士奇"]
// Uncaught TypeError: dog2.sayName is not a function
无法实现超类prototype的复用
原型链方式能够弥补借用构造函数方式的缺点,借用构造函数方式也能弥补原型链方式的缺点,那么我们组合一下不就好了?
function SuperType(name){
this.name = name;
this.types = ["金毛","哈士奇"];
}
SuperType.prototype.sayName = function(){
return this.name;
};
function SubType(name){
SuperType.call(this,name);
}
//继承方法,通过原型链
SubType.prototype = new SuperType();
//改变构造函数
SubType.prototype.constructor = SubType;
//不做运行测试了 应该都明白了集前两种优点于一身
无论什么情况,都会调用两次超类的构造函数
原型式继承要求必须有一个对象作为另一个对象的基础
var person = {
name:"bai",
firends:["zhou","li"]
}
var per1 = Object.create(person);
var per2 = Object.create(person);
per1.friends.push("wang");
console.log(per2.friends);
//["zhou","li","wang"]
这怎么和原型链继承一样?
Object.create到底做了什么?
Object.create是es5新增的方法
其实现是
function object(o){
function F(){}
F.prototype = o;
return new F();
}
对比一下原型链继承
function SubType(){
this.name = "大白"
}
//继承了SuperTyoe
SubType.prototype = new SuperType();
这tm不就是一样的吗~~,就简化了一步自定义的构造,依然是有原型链的缺陷。
function createAnother(o){
var clone = object(o);
//增强对象
clone.say = function(){
alert("hi");
}
return clone;
}
function SuperType(name){
this.name = name;
this.types = ["金毛","哈士奇"];
}
SuperType.prototype.sayName = function(){
return this.name;
};
function SubType(name){
//调用超类构造函数
this.name ="大白"
SuperType.call(this,name);
}
function inherit(subtype,supertye){
//创建超类原型副本
var proto = Object.create(supertye.prototype);
//添加构造函数为子类
proto.constructor = subtype;
//子类原型指向超类的副本
subtype.prototype = proto;
}
//实现继承
inherit(SubType,SuperType);
SubType.prototype.sayHost = function(){
return "白哥"
};
var dog1 = new SubType("小白");
var dog2 = new SubType("老白");
dog1.types.push('柯基');
console.log(dog1.sayName(),dog2.sayName());
console.log(dog1.types,dog2.types);
只有一次超类构造函数的调用
还能够正常使用instanceof 和 isPrototypeOf()
并且避免了prototype上的多余的不必要的属性(因为通过 SuperType.call(this,name);已经继承过来了)