继承:就是重复利用另外一个对象的属性和方法。这种方式可以大大减少代码的重复性,提高代码的可维护性和可扩展性。
一、原型链继承
让一个构造函数的原型是另一个类型的实例,那么这个构造函数new出来的实例就具有该实例的属性。
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
原型链继承是JS中最常见的继承方式之一。例:
复制代码
function Netname() {
this.name = 'SouthernWind';
}
Netname.prototype.sayName = function() {
console.log('你好' + this.name);
}
function southernWinds() {}
SouthernWind.prototype = new Netname();
var southernWinds = new SouthernWind();
SouthernWind.name = 'SouthernWind';
SouthernWind.sayName(); // 你好 SouthernWind
在这个例子中,我们定义了一个Netname构造函数,它有一个属性name和一个方法sayName。然后我们定义了一个SouthernWind构造函数,并将它的原型指向Netname的实例。这样,SouthernWind就可以继承Netname的属性和方法了。
二、构造函数继承
构造函数继承是通过在子类构造函数中调用父类构造函数来实现继承的。例如:
复制代码
function Netname(name) {
this.name = name;
}
Netname.prototype.sayName = function() {
console.log('你好' + this.name);
}
function SouthernWind(name) {
Netname.call(this, name);
}
var southernWinds = new SouthernWind('SouthernWind');
southernWinds.sayName(); // TypeError: SouthernWind.sayName is not a function
在这个例子中,我们定义了一个Netname构造函数,它有一个属性name和一个方法sayName。然后我们定义了一个SouthernWind构造函数,并在其中调用了Netname构造函数。这样,SouthernWind就可以继承Netname的属性了。但是,由于SouthernWind的原型没有指向Netname的原型,所以它无法继承Netname的方法。
关于优缺点:
优点:构造函数继承的优点是可以继承父类的属性和方法,同时可以在子类中添加新的属性和方法。这种继承方式比较简单,易于理解和实现。
缺点:如果父类的构造函数中有一些复杂的逻辑,子类必须重复实现这些逻辑,导致代码冗余。另外,如果父类的构造函数中有一些私有属性或方法,子类无法访问这些属性或方法。
三、组合继承
组合继承是将原型链继承和构造函数继承结合起来的一种继承方式。它的原理是通过在子类构造函数中调用父类构造函数来继承属性,然后将子类的原型指向父类的实例来继承方法。例如:
复制代码
function Netname(name) {
this.name = name;
}
Netname.prototype.sayName = function() {
console.log('My name is ' + this.name);
}
function SouthernWind(name) {
Netname.call(this, name);
}
SouthernWind.prototype = new Animal();
SouthernWind.prototype.constructor = SouthernWind;
var southernWinds = new SouthernWind('SouthernWind');
southernWinds.sayName(); // My name is SouthernWind
在这个例子中,我们定义了一个Netname构造函数,它有一个属性name和一个方法sayName。然后我们定义了一个SouthernWind构造函数,并在其中调用了Netname构造函数。接着,我们将SouthernWind的原型指向Netname的实例,并将SouthernWind的构造函数指向SouthernWind本身。这样,SouthernWind就可以同时继承Netname的属性和方法了。
优缺点
优点: 解决了原型链继承和借用构造函数继承造成的影响。
缺点: 无论在什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部
四、ES6中的继承
在ES6中,我们可以使用class关键字来定义类和继承。例如:
复制代码
class Netname {
constructor(name) {
this.name = name;
}
sayName() {
console.log('你好' + this.name);
}
}
class SouthernWind extends Netname {
constructor(name) {
super(name);
}
}
var southernWind = new SouthernWind('SouthernWind');
southernWind.sayName(); // 你好 SouthernWind
在这个例子中,我们定义了一个Netname类,它有一个构造函数和一个方法sayName。然后我们定义了一个SouthernWind 类,并使用extends关键字来继承Netname类。在SouthernWind 的构造函数中,我们使用super关键字来调用父类的构造函数。这样,SouthernWind 就可以继承Netname的属性和方法了。
结尾
在JS中,我们可以使用原型链继承、构造函数继承、组合继承和ES6中的继承来实现继承。每种继承方式都有其优缺点,我们需要根据具体情况来选择合适的继承方式。