new

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

new 运算符允许开发者创建一个用户定义的对象类型或内置对象类型之一的实例,这些对象类型都具有构造函数。

试一试

function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}

const car1 = new Car("Eagle", "Talon TSi", 1993);

console.log(car1.make);
// Expected output: "Eagle"

语法

js
new constructor
new constructor()
new constructor(arg1)
new constructor(arg1, arg2)
new constructor(arg1, arg2, /* …, */ argN)

参数

constructor

指定对象实例类型的类或函数。该表达式可以是任何具有足够优先级的内容,包括标识符、属性访问器或另一个 new 表达式,但不允许使用可选链式操作符

arg1, arg2, …, argN

将传递给 constructor 的值列表。new Foo 等同于 new Foo(),即,如果没有指定参数列表,Foo 将在没有参数的情况下被调用。

描述

当一个函数使用 new 关键字调用时,该函数将被用作构造函数。new 将执行以下操作:

  1. 创建一个空白的普通 JavaScript 对象。为方便起见,我们称之为 newInstance

  2. 如果构造函数的 prototype 属性是一个 Object,则将 newInstance 的 [[Prototype]] 指向构造函数的 prototype 属性。否则,newInstance 仍将是一个普通对象,其 [[Prototype]] 为 Object.prototype

    注意:添加到构造函数的 prototype 属性中的属性/对象因此可供由该构造函数创建的所有实例访问。

  3. 使用给定参数执行构造函数,将 newInstance 绑定为 this 上下文(即,构造函数中所有对 this 的引用现在都指向 newInstance)。

  4. 如果构造函数返回一个非原始值,则此返回值将成为整个 new 表达式的结果。否则,如果构造函数不返回任何内容或返回原始值,则返回 newInstance。(通常构造函数不返回值,但它们可以选择这样做以覆盖正常的对象创建过程。)

只能使用 new 运算符实例化——尝试不使用 new 调用类将抛出 TypeError

使用用户定义的构造函数创建对象需要两个步骤:

  1. 通过编写一个指定其名称和属性的函数来定义对象类型。例如,一个用于创建对象 Foo 的构造函数可能如下所示:

    js
    function Foo(bar1, bar2) {
      this.bar1 = bar1;
      this.bar2 = bar2;
    }
    
  2. 使用 new 创建对象的实例。

    js
    const myFoo = new Foo("Bar 1", 2021);
    

注意:一个对象可以有一个属性,该属性本身是另一个对象。请参阅下面的示例。

你总是可以向先前定义的对象实例添加属性。例如,语句 car1.color = "black"car1 添加了一个属性 color,并为其赋值 "black"

然而,这不影响任何其他对象。要将新属性添加到所有相同类型的对象,你必须将该属性添加到构造函数的 prototype 属性中。这定义了一个由该函数创建的所有对象共享的属性,而不是仅仅由该对象类型的一个实例共享的属性。以下代码向所有 Car 类型的对象添加一个值为 "original color"color 属性,然后仅在实例对象 car1 中将其值覆盖为字符串 "black"。有关更多信息,请参阅原型

js
function Car() {}
const car1 = new Car();
const car2 = new Car();

console.log(car1.color); // undefined

Car.prototype.color = "original color";
console.log(car1.color); // 'original color'

car1.color = "black";
console.log(car1.color); // 'black'

console.log(Object.getPrototypeOf(car1).color); // 'original color'
console.log(Object.getPrototypeOf(car2).color); // 'original color'
console.log(car1.color); // 'black'
console.log(car2.color); // 'original color'

注意:虽然构造函数可以像任何常规函数一样被调用(即,不带 new 运算符),但在这种情况下不会创建新对象,并且 this 的值也不同。

一个函数可以通过检查 new.target 来判断它是否使用 new 调用。只有当函数在没有 new 的情况下被调用时,new.target 才是 undefined。例如,你可以有一个函数,它在被调用时和被构造时表现不同:

js
function Car(color) {
  if (!new.target) {
    // Called as function.
    return `${color} car`;
  }
  // Called with new.
  this.color = color;
}

const a = Car("red"); // a is "red car"
const b = new Car("red"); // b is `Car { color: "red" }`

在 ES6 引入之前,大多数 JavaScript 内置对象既可调用又可构造,尽管它们中的许多表现出不同的行为。举几个例子:

  • Array()Error()Function() 作为函数或构造函数调用时行为相同。
  • Boolean()Number()String() 在作为函数调用时将其参数强制转换为相应的原始类型,在构造时返回包装对象。
  • Date() 在作为函数调用时返回一个表示当前日期的字符串,等同于 new Date().toString()

ES6 之后,语言对哪些是构造函数,哪些是函数变得更加严格。例如:

  • Symbol()BigInt() 只能在不带 new 的情况下调用。尝试构造它们将抛出 TypeError
  • ProxyMap 只能用 new 构造。尝试调用它们将抛出 TypeError

示例

对象类型和对象实例

假设你想要为汽车创建一种对象类型。你希望这种类型的对象被称为 Car,并且你希望它具有品牌、型号和年份的属性。为此,你将编写以下函数:

js
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}

现在你可以按如下方式创建名为 myCar 的对象

js
const myCar = new Car("Eagle", "Talon TSi", 1993);

此语句创建 myCar 并为其属性分配指定的值。然后 myCar.make 的值是字符串 "Eagle",myCar.year 是整数 1993,等等。

你可以通过调用 new 创建任意数量的 car 对象。例如:

js
const kensCar = new Car("Nissan", "300ZX", 1992);

本身是另一个对象的对象属性

假设你定义一个名为 Person 的对象,如下所示:

js
function Person(name, age, sex) {
  this.name = name;
  this.age = age;
  this.sex = sex;
}

然后实例化两个新的 Person 对象,如下所示:

js
const rand = new Person("Rand McNally", 33, "M");
const ken = new Person("Ken Jones", 39, "M");

然后你可以重写 Car 的定义,以包含一个接受 Person 对象的 owner 属性,如下所示:

js
function Car(make, model, year, owner) {
  this.make = make;
  this.model = model;
  this.year = year;
  this.owner = owner;
}

要实例化新对象,你可以使用以下内容:

js
const car1 = new Car("Eagle", "Talon TSi", 1993, rand);
const car2 = new Car("Nissan", "300ZX", 1992, ken);

在创建新对象时,上述语句不是传递字面字符串或整数值,而是将对象 randken 作为所有者的参数传递。要查明 car2 的所有者姓名,你可以访问以下属性:

js
car2.owner.name;

new 与类一起使用

js
class Person {
  constructor(name) {
    this.name = name;
  }
  greet() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const p = new Person("Caroline");
p.greet(); // Hello, my name is Caroline

规范

规范
ECMAScript® 2026 语言规范
# sec-new-operator

浏览器兼容性

另见