面试题答案
一键面试- 构造函数继承(经典继承、借用构造函数)
- 构建原型链:在子构造函数内部通过
call
或apply
方法调用父构造函数,将父构造函数的属性和方法复制到子构造函数的实例上。它并没有真正构建原型链,只是在子实例上复制了父实例的属性和方法。 - 示例代码:
- 构建原型链:在子构造函数内部通过
function Parent(name) {
this.name = name;
this.sayName = function() {
console.log('My name is'+ this.name);
};
}
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
- **作用**:优点是可以向父构造函数传递参数,并且每个子实例都有自己独立的属性副本,相互不影响。缺点是无法共享方法,每个实例都有相同方法的副本,浪费内存。
2. 原型链继承 - 构建原型链:将子构造函数的原型对象设置为父构造函数的一个实例,这样就形成了原型链。子构造函数的实例会通过原型链找到父构造函数原型上的属性和方法。 - 示例代码:
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log('My name is'+ this.name);
};
function Child(age) {
this.age = age;
}
Child.prototype = new Parent('default name');
Child.prototype.constructor = Child;
- **作用**:优点是可以共享原型上的方法,节省内存。缺点是子实例的所有属性都共享自父实例的原型,修改子实例的引用类型属性会影响其他子实例;而且在创建子实例时无法向父构造函数传递参数。
3. 组合继承(构造函数 + 原型链继承)
- 构建原型链:结合了构造函数继承和原型链继承的优点。通过构造函数继承来初始化每个实例的属性,通过原型链继承来共享方法。先通过 call
或 apply
调用父构造函数初始化实例属性,再将子构造函数的原型设置为父构造函数的实例。
- 示例代码:
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log('My name is'+ this.name);
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
- **作用**:既可以向父构造函数传递参数,又能共享方法,避免了前两种继承方式的主要缺点,是比较常用的继承方式。
4. ES6 类继承(extends)
- 构建原型链:使用 class
和 extends
关键字实现继承。class
本质上还是基于原型链和构造函数的语法糖。extends
关键字会自动构建原型链,将子类的原型设置为父类的实例,并正确设置 constructor
等属性。
- 示例代码:
class Parent {
constructor(name) {
this.name = name;
}
sayName() {
console.log('My name is'+ this.name);
}
}
class Child extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
}
- **作用**:语法更加简洁、清晰,易于理解和维护,是 ES6 之后推荐的继承方式。它同样具备组合继承的优点,同时在处理原型链和构造函数方面更加规范和便捷。