JavaScript new关键字内部机制:能否操纵函数f创建可实例化对象fn?
能否让
new f()生成的对象可被new实例化? 首先直接给结论:可以,但不能通过修改普通对象的原型/constructor属性实现,必须让构造函数f返回一个函数对象。下面一步步拆解原因和实现方式:
先搞懂new的内部逻辑
当你执行new f()时,JS引擎会做这几件事:
- 创建一个全新的空对象(我们叫它
obj) - 把
obj.__proto__指向f.prototype - 调用
f.call(obj),把this绑定到obj上执行构造函数 - 如果
f执行后返回的是一个对象类型(包括函数、数组等),就返回这个对象;否则返回步骤1创建的obj
在你的原始代码里,f没有显式返回值,所以new f()返回的是步骤1创建的普通对象fn——它的typeof是object,本质是个没有函数能力的普通对象,自然不能被调用或者new。
为什么修改fn的原型/constructor没用?
你尝试修改fn.__proto__ = f.__proto__、fn.constructor = f.constructor,但这只是改变了fn的原型链,并没有改变它的本质类型:
- JS里的函数对象和普通对象的核心区别在于,函数对象拥有
[[Call]](允许被调用)和[[Construct]](允许被new)这两个内部插槽(引擎层面的属性,用户代码无法直接修改) - 普通对象即使把原型链指向
Function.prototype,它依然没有这两个内部插槽,所以引擎依然会把它当成普通对象,拒绝执行函数调用或者new操作 - 比如你执行
fn.call(this)时,call方法本身是Function.prototype的方法,但它需要this指向一个能被调用的函数对象,而fn不是,所以会报错
正确的实现方式:让f返回一个函数
如果我们让构造函数f显式返回一个函数,那么new f()就会返回这个函数对象——它自带[[Call]]和[[Construct]]插槽,自然可以被调用或者new:
let f = function() { // 返回一个函数,这个函数就是我们要的fn return function fnConstructor() { console.log(".fn instance."); // 可以给实例添加属性 this.name = "fn instance"; }; }; const fn = new f(); typeof fn; // "function" ✅ fn(); // 输出 ".fn instance." ✅ const fnInstance = new fn(); // 可以正常实例化 ✅ console.log(fnInstance.name); // "fn instance"
这里的fn是Function的实例,具备函数的所有能力,同时因为它本身是函数,所以可以被new实例化——完全满足你的需求。
补充:关于fn.__proto__.constructor === f的疑惑
在你的原始代码里,fn.__proto__.constructor === f为true,这是因为fn.__proto__指向f.prototype,而f.prototype的默认constructor属性就是f本身。但这个constructor属性只是个普通的指向,它不会改变fn的类型——constructor只是原型链上的一个属性,和对象的本质类型无关。
内容的提问来源于stack exchange,提问作者schen
相关产品推荐
相关产品推荐

