JavaScript实现继承的几种方式
前言
之前在Post not found: JavaScript:原型链和原型对象 JavaScript:原型链和原型对象这篇文章中讲述了原型对象和原型链之间的关系,但我们了解原型和原型链的最终目的其实是为了实现继承。
现在主流的几种继承方式有:
- 原型链继承
- 借用构造函数继承
- 组合继承
- 原型式继承
- 寄生式继承
- 寄生组合式继承
在本篇文章中,会一一的介绍这些继承方式的优缺点。
原型链
既可以继承构造函数中的属性和方法,也可以继承原型链上的属性和方法,
- 实例化子类时无法给父类传参。
- 多个实例对引用类型的操作会被篡改。
function Person() {
this.name = "张三";
this.old = 18;
}
function Student() {}
Student.prototype = new Person();
var s = new Student();
console.log(s.name);
借用构造函数
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
- 无法实现复用,每个子类都有父类实例函数的副本,影响性能
function Person() {
this.name = "张三";
this.old = 18;
}
Person.prototype.run = function() {
console.log(this.name + "在运动");
};
function Student() {
Person.call(this);
}
var s = new Student();
console.log(s.name);
组合继承
缺点就是在使用子类创建实例对象时,其原型中会存在两份相同的属性/方法。
原型式继承
- 原型链继承多个实例的引用类型属性指向相同,存在篡改的可能。
- 无法传递参数
function object(obj) {
function F() {}
F.prototype = obj;
return new F();
}
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
console.log(person.friends);
//"Shelby,Court,Van,Rob,Barbie"
console.log(person.name);
寄生式继承
- 原型链继承多个实例的引用类型属性指向相同,存在篡改的可能。
- 无法传递参数
function object(obj) {
function F() {}
F.prototype = obj;
return new F();
}
function createAnother(original) {
var clone = object(original); // 通过调用 object() 函数创建一个新对象
clone.sayHi = function() {
// 以某种方式来增强对象
alert("hi");
};
return clone; // 返回这个对象
}
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"
寄生组合式继承
这是最成熟的方法,也是现在库实现的方法
function inheritPrototype(subType, superType) {
var prototype = Object.create(superType.prototype); // 创建对象,创建父类原型的一个副本
prototype.constructor = subType; // 增强对象,弥补因重写原型而失去的默认的constructor 属性
subType.prototype = prototype; // 指定对象,将新创建的对象赋值给子类的原型
}
// 父类初始化实例属性和原型属性
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
alert(this.name);
};
// 借用构造函数传递增强子类实例属性(支持传参和避免篡改)
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
// 将父类原型指向子类
inheritPrototype(SubType, SuperType);
// 新增子类原型属性
SubType.prototype.sayAge = function() {
alert(this.age);
};
var instance1 = new SubType("xyc", 23);
var instance2 = new SubType("lxy", 23);
instance1.colors.push("2"); // ["red", "blue", "green", "2"]
instance2.colors.push("3"); // ["red", "blue", "green", "3"]
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!