JavaScript constructor隐式调用与显式定义

作者:技术拾光时间:2026-07-07 08:49:12浏览:139

先拆解一个问题:JavaScript 中 constructor 这个属性,到底是如何工作的?很多人误以为它会被“隐式调用”,但实际上,constructor 本身不会被自动调用——它只是原型对象上的一个属性,指向对应的构造函数。真正被隐式关联或自动设置的,是 prototype 与 __proto

先拆解一个问题:JavaScript 中 constructor 这个属性,到底是如何工作的?很多人误以为它会被“隐式调用”,但实际上,constructor 本身不会被自动调用——它只是原型对象上的一个属性,指向对应的构造函数。真正被隐式关联或自动设置的,是 prototype 与 __proto__ 的关系,而 constructor 不过是这个关系里“附带存在”的一个引用。

JavaScript constructor隐式调用与显式定义

constructor 是什么?它从哪来?

constructor 是每个函数的 prototype 对象上默认自带的属性,值指向该函数自身。它不是语言运行时“调用”的东西,而是一个指针,用来标识“谁造出了我”。

  • 定义函数时,引擎会自动为它的 prototype 添加 constructor: 指向该函数。
  • 举个例子:function Person() {} 之后,Person.prototype.constructor === Person(结果为 true)。
  • 实例对象本身没有 constructor 属性,但可以通过原型链访问到:new Person().__proto__.constructor === Person。

显式定义 constructor 的常见场景

当手动重写函数的 prototype 时,constructor 会丢失,必须显式恢复,否则会破坏原型链的可追溯性。

  • 错误写法:Person.prototype = { say() { } }; —— 此时 Person.prototype.constructor 指向 Object,不再是 Person。
  • 正确补救:Person.prototype = { say() {}, constructor: Person };
  • 更稳妥的做法:Object.defineProperty(Person.prototype, 'constructor', { value: Person, enumerable: false }),避免遍历时暴露。

为什么 constructor 重要?

它虽不参与执行逻辑,但在以下场景里确实有实际作用:

  • instanceof 判断依赖原型链,但在调试或序列化时,常需要通过 obj.constructor.name 获取类型名。
  • 类库在做类型检查、克隆、反序列化时,经常读取 constructor 来重建实例。
  • ES6 class 编译成 ES5 后,Babel 等工具会主动修复 constructor,防止丢失。

注意:箭头函数没有 prototype,也没有 constructor

箭头函数不是构造函数,不能用 new 调用,因此它没有 prototype 属性,自然也不存在 constructor。试图访问 arrowFn.prototype 得到 undefined,访问 arrowFn.constructor 实际读取的是 Function.prototype.constructor(即 Function)。