javascript中的继承
- 继承分为两类:接口继承(interface)和实现继承(implement).
- 由于ECMAScript函数没有签名,无法实现接口继承,ECMAScript只支持实现继承,而实现继承主要是依靠原型链来实现的
原型链继承
-
缺点
-
引用值共享问题
引用值会被所有的实例(这里以两个为例,下面也将都是)共享,一个对象修改了原型属性,那么另一个的原型属性也会被修改 -
不能传参
在创建Child的实例时,不能向Parent传递参数;如果传递也不会有作用
-
/*
原型链继承:本质就是改写子类中的proptotype的指向,使其指向父类,这样就能继承父类的属性和方法
*/
// 手机案例
function Phone(band, color) {
this.band = band;
this.color = color;
}
Phone.prototype.telephone = function () {
console.log(`品牌:${this.band},颜色:${this.color},能打电话`);
}
function NewPhone(band, color) {
this.band = band;
this.color = color;
}
NewPhone.prototype = new Phone();
NewPhone.prototype.playGame = function () {
console.log(`品牌:${this.band},颜色:${this.color},能玩游戏`);
}
var oldPhone = new Phone("老式手机", "黑色");
oldPhone.telephone(); // 品牌:老式手机,颜色:黑色,能打电话
var newPhone = new NewPhone("新型手机", "花色");
newPhone.telephone();// 品牌:新型手机,颜色:花色,能打电话
newPhone.playGame();// 品牌:新型手机,颜色:花色,能玩游戏
借用构造函数继承(经典继承)
在子类构造函数中调用父类构造函数,利用用call方法在将来创建的子类实例中调用父类的构造函数
- 优点:
1.解决了引用值共享的问题
2.可以通过Child向Parent传参 - 缺点:
1.多执行了一次函数 call
2.Parent上的原型不能被继承
function Father(name) {
this.name = name;
this.obj = {
name: "AAA"
}
}
function Son(name, age) {
Father.call(this, name)
this.age = age;
}
var p1 = new Son("孙悟空", 30);
p1.obj.name = "BBB"
console.log(p1.name, p1.age, p1.obj);// 孙悟空 30 {name: "BBB"}
var p2 = new Son("杜克",20)
console.log(p2.name, p2.age, p2.obj);// 杜克 20 {name: "AAA"}
组合继承
集原型链和借用构造函数之长
- 缺点:函数多执行了一次call,调用了两次父类的构造函数,第一次是在子类的原型指向父类的实例时,第二次是执行call时
function Animal(name, color) {
this.name = name;
this.color = ["黑色", "白色"]
}
Animal.prototype.showAttribute = function () {
console.log(`动物的名字:${this.name} 颜色:${this.color}`);
}
function Dog(name, age) {
Animal.call(this, name);
this.age = age;
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
Dog.prototype.sayHi = function () {
console.log(`动物的名字:${this.name} 颜色:${this.color} 年龄:${this.age} 汪汪汪`);
}
var dog = new Dog("大黄", 8);
dog.showAttribute();// 动物的名字:大黄 颜色:黑色,白色
dog.color.push("黄色")
dog.sayHi();// 动物的名字:大黄 颜色:黑色,白色,黄色 年龄:8 汪汪汪
var dog2 = new Dog("小红",7);
dog2.showAttribute();// 动物的名字:大黄 颜色:黑色,白色
dog2.color.push("红色")
dog2.sayHi();// 动物的名字:小红 颜色:黑色,白色,红色 年龄:7 汪汪汪
原型式继承
以一个对象为基础,创建另一个对象,新创建的对象继承了基础对象,并且可以扩充新对象的属性和方法
- 缺点: 包含引用类型的属性值始终都会共享相应的值,和原型链继承一样。
/*
ES5 通过新增 Object.create()方法规范化了原型式继承,此方法可以接受两个参数,
第一个参数最为新对象原型的对象 和一个为新对象定义额外属性的对象.
*/
function object(o) {
function F() { }
F.prototype = o;
return new F();
}
var person = {
name: "人类",
attribute:["走路","跑步","睡觉"],
run: function () {
console.log(`我是${this.name},我能${this.attribute}`);
}
}
var birdMan = object(person);
birdMan.name = "鸟人"
birdMan.attribute.push("飞行");
birdMan.run();// 我是鸟人,我能走路,跑步,睡觉,飞行
var per = object(person);
per.run();// 我是人类,我能走路,跑步,睡觉,飞行
寄生式继承
- 优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
- 缺点:
1.引用类型的值还是会共享,和原型链继承一样
2.没用到原型,无法复用。
var person = {
name: "人类",
attribute:["走路","跑步","睡觉"],
run: function () {
console.log(`我是${this.name},我能${this.attribute}`);
}
}
function creatAnother(origin){
var clone = Object.create(origin);
clone.sayHi = function(){
console.log("I'am clone");
}
return clone;
}
var per1 = creatAnother(person);
per1.run();// 我是人类,我能走路,跑步,睡觉
per1.sayHi();// I'am clone
per1.attribute.push("游泳")
var per2 = creatAnother(person);
per2.run(); // 我是人类,我能走路,跑步,睡觉,游泳
寄生组合式继承
最完美的继承,只调用了一次父类的构造函数
function inheritPrototype(son, father) {
var clonePrototype = Object.create(father.prototype);// 复制父类的原型
clonePrototype.constructor = son;// 父类的原型指向子类构造函数
son.prototype = clonePrototype;// 子类原型指向父类原型,原型对原型
}
function Animal(name, color) {
this.name = name;
this.color = ["黑色", "白色"]
}
Animal.prototype.showAttribute = function () {
console.log(`动物的名字:${this.name} 颜色:${this.color}`);
}
function Dog(name, age) {
Animal.call(this, name);
this.age = age;
}
inheritPrototype(Dog, Animal);
Dog.prototype.sayHi = function () {
console.log(`动物的名字:${this.name} 颜色:${this.color} 年龄:${this.age} 汪汪汪`);
}
var dog = new Dog("大黄", 8);
dog.color.push("黄色");
dog.showAttribute();// 动物的名字:大黄 颜色:黑色,白色,黄色
dog.sayHi();// 动物的名字:大黄 颜色:黑色,白色,黄色 年龄:8 汪汪汪
var dog2 = new Dog("小红", 9);
dog2.color.push("红色")
dog2.showAttribute();// 动物的名字:小红 颜色:黑色,白色,红色
dog2.sayHi();// 动物的名字:小红 颜色:黑色,白色,红色 年龄:9 汪汪汪