将方法挂载到原型或构造函数:二者差异及优劣分析
嘿,这个问题问到点子上了!虽然你测试里两种写法调用起来效果完全一致,但它们在内存占用、继承特性、代码维护性上的差异可不小,咱们掰开揉碎了说:
1. 内存效率天差地别
当你把方法直接写在构造函数里时,每创建一个实例,都会生成一个全新的函数副本。比如你创建1000个Aircraft实例,就会有1000个一模一样的totalCost函数在内存里躺着,纯纯的资源浪费。
但把方法挂载到原型上时,这个方法是所有实例共享的——不管你创建多少个实例,内存里只有这一个totalCost函数,所有实例都会通过原型链找到它。这在实例数量多的时候,内存节省效果特别明显。
咱们用代码验证下:
// 构造函数挂载方法 function Aircraft1(a,b,c) { this.manufacturer = a; this.totalCost = function() { return b*c; }; } const planeA = new Aircraft1("Boeing",2,500000); const planeB = new Aircraft1("Airbus",4,600000); console.log(planeA.totalCost === planeB.totalCost); // false,是两个不同的函数 // 原型挂载方法 function Aircraft2(a,b,c) { this.manufacturer = a; this.numberOfEngines = b; this.costPerEngine = c; } Aircraft2.prototype.totalCost = function() { return this.numberOfEngines * this.costPerEngine; }; const planeC = new Aircraft2("Boeing",2,500000); const planeD = new Aircraft2("Airbus",4,600000); console.log(planeC.totalCost === planeD.totalCost); // true,共享同一个函数
2. 继承和扩展更灵活
如果你后续要创建Aircraft的子类(比如FighterJet),原型挂载的方法可以直接被子类继承,不用重复定义。而且如果后续需要修改这个方法,只需要修改原型上的版本,所有实例(包括子类实例)都会自动用上新的方法。
但如果方法在构造函数里,子类要么得重新写一遍方法,要么得在子类构造函数里调用父类构造函数,不仅冗余,后续修改也得改多个地方,维护成本很高。
3. 代码结构更清晰
把方法集中放在原型上,能让构造函数只负责初始化实例属性,方法和属性分离,代码逻辑更清晰,别人读你的代码时一眼就能区分“哪些是实例独有的属性”,“哪些是所有实例共享的方法”。
那什么时候适合把方法写在构造函数里?
当然也有例外:如果你的方法需要访问构造函数内部的私有闭包变量(也就是构造函数里定义的、没挂载到this上的变量),那只能把方法写在构造函数里。比如:
function Aircraft(a,b,c) { const secretCode = "TOP_SECRET"; // 私有闭包变量 this.manufacturer = a; // 这个方法需要访问secretCode,只能放在构造函数里 this.getSecretInfo = function() { return `${this.manufacturer} - ${secretCode}`; }; }
这种情况下,原型方法拿不到secretCode,只能用构造函数内的方法来实现。
总结一下:绝大多数场景下,优先把方法挂载到原型上——省内存、好继承、易维护;只有当方法依赖构造函数的私有闭包变量时,才考虑放在构造函数里。
内容的提问来源于stack exchange,提问作者DR01D

