JavaScript中的继承方式
1.原型继承
最简单的继承方式,实现时主要需要搞清楚prototype与对象原型[[prototype]]的关系
简单点说就是:
[[prototype]]是对象里的一个隐藏属性,指向对象的上一级原型,使用__proto__可以获取到这个属性,在现代js中,也可以使用Object.getPrototypeOf()函数来获取对象的原型。
而prototype是构造函数中的一个属性,它是一个对象,里面有一个constructor属性指向这个构造函数,当使用构造函数构造对象时,构造的这个对象的[[prototype]]属性指向这个构造函数的prototype属性。
示意图:
图片来源:zh.javascript.info/function-pr…
function Animal(){
this.name = 'animal';
console.log("zhixingle");
}
Animal.prototype.getName = function(){
return this.name;
}
function Dog() {};
Dog.prototype = new Animal();
console.dir(dog.name) //'animal'
原型继承的存在的问题:
无法向父类传递参数
2.借用构造函数实现继承
function Animal(name,color){
this.name = name;
this.color = color;
this.getName = ()=>this.name;
}
function Dog(name,color,price){
Animal.call(this,name,color);
this.price = price;
}
function Cat(name,color,price){
Animal.call(this,name,color);
this.price = price;
}
let dog = new Dog('小羊',['white','black'],'3000$');
let cat = new Cat('圆圆',['grey','yellow'],'2000$');
console.log(dog.getName===cat.getName);//**false
这个方法解决了原型继承不能给父类传递参数的不足,但是它也有自己的不足:
1.不能继承原型的属性,这个方法本质上还是将属性值付给了自己
2.不能实现函数复用,每次都需要创建相同功能的函数,造成不必要的浪费。如上方的代码中:console.log(dog.getName===cat.getName);//**false
3.组合继承
function Animal(name,color){
this.name = name;
this.color = color;
}
Animal.prototype.getName = ()=>this.name;
function Dog(name,color,price){
Animal.call(this,name,color);
this.price = price;
}
function Cat(name,color,price){
Animal.call(this,name,color);
this.price = price;
}
Dog.prototype = new Animal();
let dog = new Dog('小羊',['white','black'],'3000$');
console.log(dog);
let cat = new Cat('圆圆',['grey','yellow'],'2000$');
console.log(cat);
console.log(cat.getName===dog.getName);//true
这个方法结合了前面两种实现方法,结合了前面两种方法的优点,同时解决了函数不能复用的缺陷。
当然它也有缺点:
重复运行父类的实例,为原型添加了不必要的属性.
4.寄生组合继承
function inherit(parent, child){
const Super = function(){};
Super.prototype = parent.prototype;
child.prototype = new Super();
//修正constructor属性
child.prototype.constructor = child;
}
// 父类
function Animal(name, color){
this.name = name;
this.color = color;
}
Animal.prototype.greet = function() {
console.log(`hello my name is ${this.name}`)
}
// 子类
function Dog(name,color,price){
Animal.call(this, name, color);
this.price = price;
}
// 子类
function Cat(name, color, price){
Animal.call(this, name, color);
this.price = price;
}
inherit(Animal, Cat)
inherit(Animal, Dog)
const cat = new Cat('tome', 'orange', '1000CNY')
cat.greet()
解决了前三种的所有问题
5.使用es6的class实现继承
class Animal{
constructor(name='animal',color){
this.name = name;
this.color = color;
console.log("父类初始化");
}
getName(){
return this.name;
}
}
class Dog extends Animal{
constructor(name,color,price){
super(name,color);
console.log(this.name);
this.price = price;
}
}
class Cat extends Animal{
constructor(name,color,price){
super(name,color);
this.price = price;
}
}
let dog = new Dog('小羊',['white','black'],'3000$');
console.log(dog);
let cat = new Cat('圆圆',['grey','yellow'],'2000$');
console.log(cat);
console.log(cat.getName===dog.getName);
参考文章:
1.zh.javascript.info/prototype-i…