如何像Chrome开发者控制台那样获取构造函数名称?
问题解析:Chrome控制台显示构造函数名称但标准JS无法获取的原因
先看你提供的代码执行过程:
> var exports = {} undefined > (function(){var Foo = function() {}; Foo.prototype = ""; exports.bar = Foo;})() undefined > obj = new exports.bar(); Foo {} > obj.constructor.name 'Object' > obj.__proto__ {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} > obj.__proto__.name undefined > obj Foo {}
核心矛盾点:Chrome控制台显示实例是Foo {},但通过标准JS API(constructor.name)只能拿到Object,背后是V8引擎内部追踪机制和ECMAScript标准行为的差异:
1. 标准JS中constructor.name失效的原因
你在代码里做了一个关键操作:Foo.prototype = ""。根据ECMAScript标准:
- 构造函数的
prototype属性要求是对象(或null),如果赋值为原始值(比如字符串""),执行new操作时,JS会自动将实例的__proto__指向默认的Object.prototype。 - 所以
new exports.bar()创建的obj,其原型链已经和Foo.prototype完全断开,obj.constructor自然指向Object,obj.constructor.name就是"Object"。
2. Chrome控制台能显示Foo的原因
Chrome使用的V8引擎会给函数额外记录一个内部名称槽([[Name]]):
- 当你用
var Foo = function() {}这种方式创建函数时,V8会把变量名Foo作为这个函数的内部名称,这个名称不会因为你把函数赋值给其他变量(比如exports.bar)、修改原型而丢失。 - 控制台打印对象时,会绕过标准的原型链,直接追溯创建该实例的构造函数的内部名称——哪怕实例的原型链已经被修改,引擎依然能关联到最初的构造函数
Foo,所以会显示Foo {}。 - 这是V8引擎的实现细节,不属于ECMAScript标准,其他JS引擎的控制台可能不会有这个行为。
验证补充
如果你在控制台直接打印exports.bar.name,会发现它的值是"Foo"——这是因为ES6之后,V8会把函数的内部名称同步到公开的name属性,但因为实例的原型链已经和Foo断开,所以从实例上拿不到这个值。
内容的提问来源于stack exchange,提问作者IttayD
相关产品推荐
相关产品推荐

