面试题答案
一键面试原型链继承
- 原理:通过将子类的原型对象指向父类的实例,实现继承。即
SubType.prototype = new SuperType()
。这样子类就可以访问到父类原型上的属性和方法。 - 优点:实现简单,父类新增的原型方法和属性,子类都能访问到。
- 缺点:所有实例共享父类原型对象上的属性,一个实例对引用类型属性的修改会影响其他实例;不能在不影响其他实例的情况下,向构造函数传递参数。
- 应用场景:如果属性都是基本类型且不需要传递参数给构造函数,可考虑使用,如简单的对象继承场景。
构造函数继承
- 原理:在子类构造函数内部通过
call
或apply
方法调用父类构造函数,将父类的属性和方法复制到子类实例上。如function SubType() { SuperType.call(this, arguments); }
- 优点:可以在子类构造函数中向父类构造函数传递参数;每个实例都有自己的属性副本,不会相互影响。
- 缺点:无法复用父类原型上的方法,每个实例都有一份父类方法的副本,占用内存较大。
- 应用场景:当需要为每个实例创建独立的属性副本,且对内存占用不太敏感时使用。
组合继承
- 原理:结合了原型链继承和构造函数继承。先通过构造函数继承方式初始化子类实例的属性,再通过原型链继承方式让子类共享父类原型上的方法。即
function SubType() { SuperType.call(this, arguments); } SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType;
- 优点:既能复用父类原型上的方法,又能为每个实例创建独立的属性副本,可以向父类构造函数传递参数。
- 缺点:父类构造函数会被调用两次,一次是在
new SuperType()
创建子类原型时,一次是在SuperType.call(this)
初始化子类实例时,造成不必要的性能损耗。 - 应用场景:在性能要求不是极高,同时需要复用父类原型方法和为实例创建独立属性副本的场景下适用。
寄生组合继承
- 原理:通过创建一个临时构造函数,让这个临时构造函数的原型指向父类原型,然后创建这个临时构造函数的实例,并将其作为子类的原型。即
function inheritPrototype(SubType, SuperType) { let prototype = Object.create(SuperType.prototype); prototype.constructor = SubType; SubType.prototype = prototype; }
然后在子类构造函数中通过call
调用父类构造函数初始化属性。 - 优点:解决了组合继承中父类构造函数被调用两次的问题,性能较好;既能复用父类原型上的方法,又能为每个实例创建独立的属性副本,可以向父类构造函数传递参数。
- 缺点:实现相对复杂。
- 应用场景:在性能要求较高且需要复用父类属性和方法的场景下,寄生组合继承是最佳选择,因为它避免了组合继承中不必要的父类构造函数调用,同时具备组合继承的优点。