面试题答案
一键面试寄生组合式继承原理
- 基础概念:寄生组合式继承是一种实现JavaScript继承的模式,它结合了寄生式继承和组合继承的优点。核心思想是通过创建一个中间函数,让这个中间函数的原型指向父类的原型,从而实现原型链的继承,同时又避免了组合继承中重复调用父类构造函数的问题。
- 实现步骤:
- 首先创建一个临时的构造函数。
- 然后将这个临时构造函数的原型指向父类的原型。
- 创建一个新对象,这个新对象的原型是上述临时构造函数的实例,这样新对象就拥有了父类原型上的属性和方法。
- 最后在子类的构造函数中调用父类的构造函数,以确保子类实例拥有父类实例的属性。
与其他继承方式相比的优势
- 与原型链继承相比:
- 原型链继承问题:原型链继承会导致所有实例共享原型对象上的属性,如果原型对象上的属性是引用类型,一个实例对其修改会影响其他实例。例如:
function Animal() {}
Animal.prototype.species = '动物';
function Dog() {}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
let dog1 = new Dog();
let dog2 = new Dog();
dog1.species = '犬科';
console.log(dog2.species); // '犬科',共享导致影响
- **寄生组合式继承优势**:通过在子类构造函数中调用父类构造函数,为每个子类实例单独创建属性,避免了共享引用类型属性的问题。
2. 与借用构造函数继承相比: - 借用构造函数继承问题:借用构造函数继承无法继承父类原型上的属性和方法,因为它只是在子类构造函数中调用父类构造函数,没有建立原型链关系。例如:
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + '发出声音');
};
function Dog(name) {
Animal.call(this, name);
}
let dog = new Dog('旺财');
dog.speak(); // Uncaught TypeError: dog.speak is not a function
- **寄生组合式继承优势**:既通过调用父类构造函数初始化实例属性,又通过设置原型链继承了父类原型上的属性和方法。
代码示例对比
- 原型链继承:
function Parent() {
this.value = 10;
}
Parent.prototype.getValue = function() {
return this.value;
};
function Child() {}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
let child1 = new Child();
let child2 = new Child();
child1.value = 20;
console.log(child2.getValue()); // 20,共享属性问题
- 借用构造函数继承:
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log('我是' + this.name);
};
function Child(name) {
Parent.call(this, name);
}
let child = new Child('小明');
child.sayName(); // Uncaught TypeError: child.sayName is not a function
- 寄生组合式继承:
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log('我是' + this.name);
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
function inheritPrototype(child, parent) {
let prototype = Object.create(parent.prototype);
prototype.constructor = child;
child.prototype = prototype;
}
inheritPrototype(Child, Parent);
let child = new Child('小红', 18);
child.sayName(); // 我是小红