为何需在构造函数原型定义函数?类及其他设计模式疑问解析
先回顾你提到的知识点:
如果使用构造函数创建对象,最好将函数定义在该对象的原型上。这样每个函数仅会存在一个实例,被所有Student对象共享。如果直接在构造函数中声明函数,每次创建新Student实例时都会复制该函数。
对应的代码示例:
function Student() { } Student.prototype.sayName = function() { console.log(this.name) }
针对你的两个疑问,解答如下:
1. 这种做法是否适用于Class和Object()构造函数?
完全适用,甚至Class本身就是构造函数的语法糖,底层逻辑和传统构造函数一致:
用Class定义的类方法,默认就挂载在类的原型上。比如:
class Student { sayName() { console.log(this.name); } }这段代码里的
sayName方法,本质就是Student.prototype.sayName,所有Student实例都会共享同一个方法实例,不会重复创建。对于
Object()构造函数,原理也一样:如果想让所有通过new Object()创建的对象共享方法,你可以把方法挂载到Object.prototype上。不过实际开发中不建议这么做,因为会污染全局所有对象的原型,引发潜在冲突,但从技术实现角度,它确实能让所有Object实例共享该方法,避免重复创建。
2. 工厂函数、模块模式为何无需这么做?
不是“无需”,而是这些模式有自己的共享方法实现方式,或者场景本身不存在重复创建的问题:
工厂函数
如果直接在工厂函数内部定义方法,确实会每次创建实例时都生成新的函数,比如:
function createStudent(name) { return { name, sayName: function() { console.log(this.name); } }; }
这种写法每次调用createStudent都会新建一个sayName函数。但工厂函数也可以通过共享方法对象来避免重复创建,比如:
// 定义一次共享方法 const studentSharedMethods = { sayName() { console.log(this.name); } }; function createStudent(name) { // 让实例继承共享方法 return Object.create(studentSharedMethods, { name: { value: name, writable: true } }); }
这样所有createStudent生成的实例都会共享studentSharedMethods里的方法,不会重复创建。只是很多开发者写工厂函数时图简便,才会直接在内部定义方法,导致重复创建的问题。
模块模式
模块模式通常用于创建单例对象,也就是整个应用里只会生成一个实例。比如:
const studentModule = (function() { let name = "Alice"; function sayName() { console.log(name); } return { sayName }; })();
这里的sayName方法只会在模块初始化时创建一次,之后不会再生成新的实例,自然不存在重复创建的问题,所以不需要像构造函数那样去考虑原型共享的事。
内容的提问来源于stack exchange,提问作者GeorgeCiesinski

