中间空函数的核心作用是切断父构造函数执行,只借用其原型对象;它通过创建无副作用的空实例,避免子类原型继承时意外初始化父类实例属性(尤其引用类型),确保方法可继承而状态不共享。

中间空函数的核心作用是“切断父构造函数的执行”,只借用父类的原型对象,不触发其构造逻辑。它不是为了“避免重复实例化”而存在,而是为了避免在设置子类原型时意外调用父类构造函数——因为一旦调用,就会创建一个带实例属性(尤其是引用类型)的父类对象,被所有子类实例共享。
为什么直接 new Parent() 会出问题
当你写 Child.prototype = new Parent(),JavaScript 真的会执行一次 Parent() 构造函数:
- 如果
Parent内部有this.name = 'xxx'这样的赋值,这个name就成了Child.prototype上的属性,所有Child实例都能读到,但改起来互相影响; - 更严重的是,像
this.hobbies = []这类引用类型属性,会被所有子实例共用——一个 push,全跟着变; - 而且你根本无法在创建
Child实例时,把参数传给这次“偷偷执行”的Parent调用。
空函数如何当好“中转站”
用一个什么也不做的函数(比如 function F() {}),让它暂时继承 Parent.prototype,再让 Child.prototype 指向它的实例——这样既拿到了干净的原型链,又绕开了父构造函数:
-
F.prototype = Parent.prototype;→ 把父类方法链挂到空函数上; -
Child.prototype = new F();→ 此时 new F() 不执行任何逻辑,只产生一个空对象,它的__proto__指向Parent.prototype; - 于是
Child实例查方法时,顺着原型链就能找到Parent.prototype上的方法,但不会沾上任何父类实例属性。
标准写法:Object.create 是更现代的替代
ES5 提供了更简洁安全的方式:Child.prototype = Object.create(Parent.prototype);
- 它内部就相当于做了上面空函数的事:创建一个新对象,其
[[Prototype]]直接设为Parent.prototype; - 不调用
Parent构造函数,不产生冗余实例,也不污染原型; - 之后别忘了补一句:
Child.prototype.constructor = Child;,否则instance.constructor会指向Parent。
组合继承里为何还要用它
组合继承(构造函数 + 原型链)本意是:用 Parent.call(this) 继承实例属性,用原型链继承方法。但如果原型链仍用 new Parent(),等于又执行了一次父构造函数——属性被初始化了两次(一次在 call,一次在 new)。用空函数或 Object.create,就能确保方法继承干净利落,只调用一次父构造函数。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











