面试题答案
一键面试优化原型与继承结构策略
- 合理设置原型属性
- 避免频繁访问原型:将经常使用的属性直接定义在实例对象上,而不是放在原型上。例如,如果一个对象的某个属性在每次实例调用时都会用到,就直接定义在构造函数内。
- 共享不变属性:对于那些所有实例都共享且不会改变的属性和方法,放在原型上。这样可以减少每个实例的内存占用。例如,对于一个
Animal
类的species
属性,如果所有动物实例的物种信息相同,就可以放在Animal.prototype
上。
- 处理循环引用问题
- 避免循环引用:在设计对象结构时,尽量避免创建对象之间的循环引用。例如,如果有
A
和B
两个对象,不要让A
引用B
,同时B
又引用A
。 - 打破循环引用:如果无法避免循环引用,在对象不再使用时,手动打破循环引用。例如,在
A
对象的dispose
方法中,将A
对B
的引用设为null
,同时在B
对象的dispose
方法中,将B
对A
的引用设为null
。
- 避免循环引用:在设计对象结构时,尽量避免创建对象之间的循环引用。例如,如果有
- 利用ES6的
class
语法进行高效继承实现- 简洁清晰:
class
语法提供了更简洁和清晰的继承语法。它基于原型链继承,但语法上更接近传统面向对象语言。例如:
- 简洁清晰:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() {
console.log(`${this.name} barks.`);
}
}
- 正确使用
super
:在子类构造函数中,必须先调用super
方法,以正确初始化继承自父类的属性。
实际项目优化后的代码示例
- 传统原型继承优化示例
// 父构造函数
function Shape(color) {
this.color = color;
}
// 共享方法放在原型上
Shape.prototype.getArea = function () {
return 0;
};
// 子构造函数
function Circle(color, radius) {
// 调用父构造函数初始化属性
Shape.call(this, color);
this.radius = radius;
}
// 设置原型链继承
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;
// 重写父类方法
Circle.prototype.getArea = function () {
return Math.PI * this.radius * this.radius;
};
- ES6 class继承示例
class Shape {
constructor(color) {
this.color = color;
}
getArea() {
return 0;
}
}
class Circle extends Shape {
constructor(color, radius) {
super(color);
this.radius = radius;
}
getArea() {
return Math.PI * this.radius * this.radius;
}
}
通过上述策略和代码示例,可以在大型JavaScript应用中优化原型与继承结构,减少内存泄漏和性能瓶颈。