new.target 是预防全局变量污染的可靠机制,它在构造函数执行瞬间拦截漏写 new 的调用,使 this 不指向全局对象,从而从源头杜绝属性意外挂载;配合严格模式可双重保险。

new.target 不能“彻底消灭”全局变量污染,但它能可靠拦截并阻止这类错误发生。 它不是修复机制,而是预防开关——在构造函数执行的一瞬间,就切断漏写 new 的调用路径,避免 this 指向全局对象(如 window 或 globalThis),从而从源头杜绝属性被意外挂到全局上。
为什么漏写 new 会污染全局
普通函数中若使用 this.xxx = value,又没用 new 调用,this 默认指向全局对象。浏览器中就是 window,Node.js 中是 globalThis。结果就是:
-
Person('Alice')→window.name = 'Alice' -
ApiClient({url: '/api'})→window.url = '/api' - 多个模块重复调用,可能覆盖彼此的同名属性
用 new.target 主动拒绝裸调用
在构造函数开头加一行判断,即可让非法调用直接失败:
- 函数写法:
if (!new.target) throw new TypeError('必须用 new 调用'); - class 写法:同样适用,
constructor()中可直接使用 - 注意:箭头函数没有
new.target,也不支持new,所以基类必须是普通函数或 class
配合严格模式效果更稳
单独用 new.target 已足够,但加上 'use strict'; 可双重保险:
- 严格模式下,裸调用时
this是undefined,不会静默绑定到全局 - 即使忘记检查
new.target,后续对this.xxx的赋值也会立即报错,而不是悄悄污染 - 两者组合,既防漏写,也防误读——错误无法绕过,也不会延迟暴露
别依赖 name 字符串做兜底
有人试图用 if (this.constructor && this.constructor.name === 'MyClass') 判断是否合法,这不可靠:
- 混淆工具可能压缩
name,变成a或空字符串 - 通过
Object.create(MyClass.prototype)创建的对象,constructor可能丢失或被篡改 -
new.target是运行时真实调用上下文,不依赖字符串、不依赖原型链,唯一且确定











