面试题答案
一键面试寄生组合式继承原理
- 原型链继承核心:通过将子类的原型指向父类的实例,这样子类就可以访问到父类原型上的属性和方法,从而实现继承。但传统的原型链继承存在问题,比如在实例化子类时,会把父类实例的属性和方法也复制一份到子类实例上,造成不必要的内存浪费。
- 借用构造函数:为了解决上述问题,在子类构造函数内部调用父类构造函数,通过
call
或apply
方法,将父类的属性和方法绑定到子类实例上。这样,每个子类实例都有自己独立的属性副本,不会相互干扰。但这种方式只能继承父类实例的属性和方法,无法继承父类原型上的属性和方法。 - 寄生组合式继承优化:结合了原型链继承和借用构造函数的优点,通过创建一个临时构造函数,将其原型指向父类的原型,然后让子类的原型等于这个临时构造函数的实例。这样既避免了在子类实例上重复创建父类实例的属性和方法,又能让子类访问到父类原型上的属性和方法。
代码实现
// 父类
function Parent(name) {
this.name = name;
this.sayName = function() {
console.log('My name is', this.name);
};
}
Parent.prototype.sayHello = function() {
console.log('Hello');
};
// 子类
function Child(name, age) {
// 借用构造函数继承父类实例属性
Parent.call(this, name);
this.age = age;
}
// 创建一个临时构造函数
function Temp() {}
// 将临时构造函数的原型指向父类的原型
Temp.prototype = Parent.prototype;
// 创建子类的原型
Child.prototype = new Temp();
// 修复子类原型的 constructor 指向
Child.prototype.constructor = Child;
// 测试
let child = new Child('John', 25);
child.sayName(); // 输出: My name is John
child.sayHello(); // 输出: Hello
console.log(child.age); // 输出: 25
可优化方向、思路及方法
- 使用
Object.create
简化步骤:现代 JavaScript 中,可以使用Object.create
方法来简化寄生组合式继承的实现。Object.create
方法会创建一个新对象,其原型为传入的对象。
// 父类
function Parent(name) {
this.name = name;
this.sayName = function() {
console.log('My name is', this.name);
};
}
Parent.prototype.sayHello = function() {
console.log('Hello');
};
// 子类
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
// 使用 Object.create 优化
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
// 测试
let child = new Child('John', 25);
child.sayName();
child.sayHello();
console.log(child.age);
- 使用
class
语法糖:ES6 引入的class
语法糖,本质上也是基于原型链的继承,但语法更简洁,代码可读性更高。
class Parent {
constructor(name) {
this.name = name;
}
sayName() {
console.log('My name is', this.name);
}
sayHello() {
console.log('Hello');
}
}
class Child extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
}
// 测试
let child = new Child('John', 25);
child.sayName();
child.sayHello();
console.log(child.age);
使用 class
语法糖不仅简化了继承的实现,还在语义上更加清晰,更符合面向对象编程的习惯。同时,class
语法在编译时还可以进行一些优化,提升性能。