原型方法在内存中只存一份,被所有实例共享;实例方法每个对象独有一份,随实例数量线性增长。前者挂载于prototype,后者定义在实例自身,影响内存占用与原型链查找。

Class 实例方法和原型方法在内存中的表现差异,核心在于“是否被多个实例共享”。原型方法只存一份,所有实例共用;实例方法每个对象独有一份,随实例数量线性增长。
原型方法:一份代码,全员共享
当你把方法定义在 class 的 prototype 上(比如在 class 声明中用普通方法语法),它会被挂载到构造函数的 prototype 对象上。这个对象在堆中只存在一个,所有通过 new 创建的实例,都通过内部 __proto__ 指向它。
- 无论创建 10 个还是 1000 个实例,
sayHello()这个函数体在内存中始终只有 1 份 - 实例访问该方法时,是沿着原型链向上查找,不复制、不重复分配
- 典型写法:
class Person { say() { return 'Hi'; } }——say就是原型方法
实例方法:每个对象自带一份
如果方法被定义在构造过程或实例属性上(比如使用箭头函数、赋值式函数表达式),它就属于该实例自身,会为每个对象单独分配内存空间。
-
this.greet = () => 'Hello';或this.run = function() {}都会在每个实例堆空间里存一份函数对象 - 创建 1000 个实例,就可能产生 1000 份相同的函数代码副本(尽管引擎可能做一定优化,但语义上仍是独立引用)
- 这类方法优先级高于原型同名方法,会屏蔽原型链上的查找
内存结构对比:四个关键角色
以 class Dog {} 为例,内存中实际存在:
- Dog 函数本身:含
prototype属性,指向原型对象 - Dog.prototype 对象:堆中唯一,存放所有原型方法和共享属性
- 实例对象(如
dog1):堆中独立分配,只存this.name等自有属性,__proto__指向 Dog.prototype - 原型链终点:Dog.prototype.__proto__ → Object.prototype → null
怎么选?看场景和规模
不需要访问 this 或依赖闭包的工具函数,可直接挂原型;需要绑定当前实例、捕获构造时上下文(比如事件回调),才考虑实例方法。
- 行为一致、调用频繁的方法(如
toString、save)——放原型 - 需绑定特定实例状态、或作为回调传给异步操作(如
onClick)——用实例方法或bind - 大量创建对象(如游戏实体、DOM 节点包装器)时,原型方法的内存优势更明显











