new调用时this指向新对象,但仅当函数为普通函数、未显式绑定、未被call/apply覆盖且未返回对象时成立;若返回对象则new结果为此对象,否则返回新实例。

new 调用时 this 确实指向新对象,但前提是函数内部不干扰它
直接说结论:new Foo() 执行时,JavaScript 引擎会创建一个空对象,并把它作为 this 传入 Foo 函数体——但这个绑定只在函数**非箭头、未显式绑定、未被 call/apply 覆盖**的前提下生效。一旦你在函数里写 this = {}(语法错误)、或用 call(null) 调用、或返回一个对象,this 就可能“失效”或被忽略。
常见错误现象:new Foo() 返回了意外的对象(比如你手动 return {x: 1}),导致实例上没挂载属性;或者函数是箭头函数,根本没法用 new(抛 TypeError: Foo is not a constructor)。
- 构造函数必须是普通函数(
function Foo() {}或class Foo),不能是箭头函数 - 若函数显式
return一个对象,则new表达式结果就是那个对象,this上的赋值被丢弃 - 若
return基本类型(return 42、return undefined),则忽略返回值,仍返回新对象
验证 this 指向:在构造函数里打印和赋值对比
最直白的办法是在函数体内加 console.log(this) 和赋值操作,然后检查实例是否如预期持有属性。
function Person(name) {
console.log('this inside constructor:', this); // 打印出 Person {}
this.name = name;
this.sayHi = function() { return `Hi, ${this.name}`; };
}
const p = new Person('Alice');
运行后你会看到 this 是一个空的 Person 实例,且 p.name 和 p.sayHi() 都可访问。但如果改成:
function BrokenPerson(name) {
this.name = name;
return { custom: true }; // ? 这行让 p.name === undefined
}
const p2 = new BrokenPerson('Bob');
此时 p2 是 { custom: true },不是 BrokenPerson 实例,this.name = name 白执行了。
class 语法下 this 的行为更稳定,但仍有陷阱
class 是语法糖,底层仍是函数,所以 this 绑定逻辑一致,但限制更多:你不能在 constructor 中漏掉 super()(子类)、不能在调用 super() 前访问 this(否则报 ReferenceError)。
- 子类构造函数中,必须在读写
this前调用super() -
class内部方法默认不可枚举,而手写函数中this.xxx = function(){}是可枚举的(影响for...in) - 类字段(
name = 'default')会在constructor开头隐式赋值到this,等价于在super()后立即执行
别依赖 this 指向做复杂逻辑,优先用显式参数或闭包
实际项目里,过度依赖 new + this 容易导致难以测试、重构困难。比如你写了个构造函数,里面根据 this.env 做分支,那单元测试就得造实例;而如果写成 function createService({ env, timeout }) { return { ping() { ... } } },就干净得多。
容易被忽略的一点:new 不是必须的。ES6+ 中很多原生类(如 Map、Promise)虽支持 new,但工厂函数(如 Promise.resolve())更常用;自定义类也建议提供静态工厂方法(Foo.fromConfig()),避免用户记错是否要加 new。










