深入解析 new 运算符的工作原理
对象实例化的核心步骤
在调用 new 运算符 时,JavaScript 会经历一组关键步骤,确保实例具备正确的原型链以及初始化逻辑的执行。第一步是创建一个空对象,并将其原型([[Prototype]])指向构造函数的 prototype 属性,从而形成实例与原型之间的关系。
随后,第二步绑定 this,使构造函数内部对 this 的赋值实际作用于新创建的对象上,从而实现属性初始化和状态设定。
第三步执行构造函数,将传入的参数作为初始化数据,完成对象的自定义字段设定,这一步决定实例的实际内容和行为。
第四步处理返回值:如果构造函数显式返回一个对象,那么该对象成为 new 表达式的结果;如果返回的是原始数据类型,则忽略该返回值,最终返回新创建的对象。这一规则是 new 行为的关键。
function Point(x, y) {this.x = x;this.y = y;
}
const p = new Point(2, 3);
console.log(p); // Point { x: 2, y: 3 }
重要结论:new 会创建一个具有原型的实例,并执行构造函数中的初始化逻辑;如果构造函数显式返回对象,则该对象会替代默认实例作为结果。
返回值与原型方法的关系
另一重要点是:如果构造函数返回了一个对象,那么该返回对象会成为 new 表达式的最终结果;返回一个原始值时则被忽略,最终还是返回新创建的实例。
下面的例子直观展示了返回对象对最终结果的影响:显式返回对象将覆盖默认实例。
function Foo() {return { custom: 'object' };
}
let f = new Foo();
console.log(f); // { custom: 'object' }
字面量对象与 new 的对比
字面量对象的特性
字面量对象的创建语法简洁高效,不涉及构造函数绑定,直接在花括号内定义属性。该方式的原型指向 Object.prototype,实例没有额外的初始化逻辑,也不会执行构造函数代码。
与使用 new 的对象相比,字面量对象的创建成本更低,但在方法复用和初始化控制方面的灵活性较低。
// 字面量对象
const a = { x: 1, y: 2 };// 构造函数 + new
function Pt(x, y) {this.x = x;this.y = y;
}
const b = new Pt(1, 2);
console.log(a.__proto__ === Object.prototype); // true
console.log(b.__proto__ === Pt.prototype); // true
性能与灵活性的权衡
字面量对象在性能和可读性上占优,适合简单数据结构;而 new 提供了更丰富的初始化逻辑和自定义原型链,适合需要共享方法和行为的场景,原型链的设计对后续扩展极为关键。
核心要点在于:新对象的原型来自构造函数的 prototype,这决定了实例能访问哪些方法及属性。

Object.create 的用法与对比
原型注入机制
使用 Object.create 可以直接创建一个新对象,并将其原型指向指定的对象,而不会调用构造函数,因此不会执行任何初始化逻辑。这让它成为实现简单原型链继承的有力工具。
它的基本签名是 Object.create(proto, properties),其中 proto 是新对象的原型对象,可以通过该方式实现对现有对象的直接继承。
const proto = { greet() { console.log('hi'); } };
const obj = Object.create(proto);
console.log(obj.__proto__ === proto); // true
和 new 的对比要点
与 new 的差异在于:不自动调用构造函数,也不绑定 this;这使得对象创建更加纯粹地实现原型继承,而不引入初始化副作用。
尽管如此,Object.create 可以实现“直接继承自某原型”的设计,在某些场景下比使用构造函数更为简洁、安全。
工厂函数:不使用 new 的对象创建模式
简单工厂函数的实现
工厂函数是返回对象的普通函数,不需要使用 new,从而避免了 this 指向的不确定性,并且便于集中控制初始化逻辑。
function createPoint(x, y) {return {x,y,sum() { return this.x + this.y; }};
}
const p = createPoint(3, 4);
console.log(p.sum()); // 7
组合与混入的设计
工厂函数还可以通过组合模式,将不同的行为注入到对象中,避免深层的原型链依赖,同时提升代码的可组合性与可维护性。
以下示例展示了如何通过“混入”实现方法的复用:无需修改原型链即可注入行为。
const withLog = (obj) => ({log() { console.log(this); return this; },...obj
});function makeWidget(label) {return withLog({label,render() { console.log('render', this.label); }});
}
const w = makeWidget('Button');
w.log().render();


