普通函数能被 new 实例化而箭头函数不能,因其缺乏 [[construct]] 内部方法和 prototype 属性,且 this 绑定机制不同:普通函数 new 时动态绑定 this,箭头函数词法继承 this。

普通函数能被 new 实例化,箭头函数不能——这不是语法限制,而是语言设计层面的底层机制差异。关键在于是否具备 [[Construct]] 内部方法,以及 this 的绑定时机。
构造能力取决于内部方法是否存在
JavaScript 规范规定,只有拥有 [[Construct]] 内部方法的函数才能用 new 调用。普通函数(包括函数声明、函数表达式)天然具备该方法;箭头函数在引擎实现中被明确排除,它没有 [[Construct]],也没有 prototype 属性。
- 普通函数调用
new Fn()时,引擎会创建空对象 → 绑定 this → 执行函数体 → 返回实例(除非显式 return 引用类型) - 箭头函数执行
new ArrowFn()会直接抛出TypeError: ArrowFn is not a constructor - 即使箭头函数体里写了
this.name = 'xxx',也无法生效——因为 new 过程根本不会触发它的执行
this 初始化机制完全不同
普通函数作为构造函数时,this 在 new 过程中被强制绑定为新创建的空对象;箭头函数根本没有 this 初始化阶段,它连 this 的绑定入口都没有。
- 普通函数中
this是运行时动态确定的,new 调用就是其中一种确定方式 - 箭头函数的 this 是词法继承的,它依赖外层作用域的 this 值,而 new 调用不提供这个上下文
- 试图用
bind或call强行改变箭头函数的 this 并不能让它获得构造能力
实际判断一个函数能否当构造函数
不必死记规则,用两行代码快速验证:
- 检查是否有
prototype属性:typeof Fn.prototype === 'object'—— 普通函数为 true,箭头函数为 undefined - 尝试 new 调用并捕获错误:
try { new Fn() } catch(e) { console.log(e.message) } - 注意:首字母大写只是命名约定,不是构造函数的判定依据;真正起作用的是函数的内部属性
什么场景下必须用普通函数
当你需要创建多个具有相同结构的对象实例,并让每个实例拥有独立属性和共享方法时,必须使用普通函数(或 class)。
- 定义类式结构:
function User(name) { this.name = name; } - 挂载原型方法:
User.prototype.sayHi = function() { console.log('Hi, ' + this.name); }; - 批量生成实例:
const u1 = new User('Alice'); const u2 = new User('Bob'); - 箭头函数在这里完全无法替代——它既不能 new,也不能通过 prototype 共享方法











