Singleton不是构造函数:两种JS单例实现为何结果不同?
为什么第二个Singleton实现会抛出“Singleton is not a constructor”错误?
这个问题的核心原因非常明确:箭头函数不能被用作构造函数,这是JavaScript箭头函数的核心设计特性决定的。我们来逐一拆解两种实现的差异:
第一种实现(正常工作)
let Singleton = (() => { let instance; function init() { return instance || (instance = this); } return init; })(); let s = new Singleton(); let s2 = new Singleton(); console.log(s == s2); // 输出 true
这里返回的init是一个普通函数,完全符合new操作符对构造函数的要求:
- 普通函数拥有自己的
prototype属性,new操作符可以基于这个原型创建新对象的原型链。 - 当用
new调用时,this会被绑定到刚创建的新实例上。 - 第一次调用
new Singleton()时,instance为undefined,因此instance = this会把新创建的实例存入闭包中的instance变量并返回;后续调用时,直接返回已存在的instance,从而实现单例模式。
第二种实现(报错)
let Singleton2 = (() => { let instance; let init = () => { return instance || (instance = this); } return init; })(); let s1 = new Singleton2(); // 抛出 Uncaught TypeError: Singleton2 is not a constructor
这里返回的init是一个箭头函数,它天生不具备作为构造函数的能力,主要有两个关键原因:
- 箭头函数没有自己的
prototype:new操作符的核心步骤之一是将新对象的__proto__指向构造函数的prototype,但箭头函数根本没有这个属性,引擎直接拒绝用new调用它。 - 箭头函数没有独立的
this绑定:箭头函数的this是继承自定义时的外层作用域(这里是IIFE的全局作用域,this指向window/global),new操作符无法为其绑定新的实例对象作为this。
就算忽略new的限制强行执行,第二个实现里的this也不会是新创建的实例,而是全局对象,最终会把全局对象存入instance,完全达不到单例的预期效果。
内容的提问来源于stack exchange,提问作者Dima Karmazin
相关产品推荐
相关产品推荐

