new

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

¥The new operator lets developers create an instance of a user-defined object type or of one of the built-in object types that has a constructor function.

Try it

语法

¥Syntax

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

参数

¥Parameters

constructor

指定对象实例类型的类或函数。

arg1, arg2, …, argN

调用 constructor 时使用的值列表。new Foo 相当于 new Foo(),即如果未指定参数列表,则不带参数调用 Foo

描述

¥Description

当使用 new 关键字调用函数时,该函数将被用作构造函数。new 将做以下事情:

¥When a function is called with the new keyword, the function will be used as a constructor. new will do the following things:

  1. 创建一个空白的、纯 JavaScript 对象。为了方便起见,我们将其称为 newInstance
  2. 如果 prototypeObject,则将 newInstance 的 [[Prototype]] 指向构造函数的 prototype 属性。否则,newInstance 保持为普通对象,并以 Object.prototype 作为其 [[Prototype]]。

    注意:因此,从构造函数创建的所有实例都可以访问添加到构造函数的 prototype 属性的属性/对象。

    ¥Note: Properties/objects added to the constructor function's prototype property are therefore accessible to all instances created from the constructor function.

  3. 使用给定参数执行构造函数,将 newInstance 绑定为 this 上下文(即构造函数中对 this 的所有引用现在都引用 newInstance)。
  4. 如果构造函数返回 non-primitive,则该返回值将成为整个 new 表达式的结果。否则,如果构造函数不返回任何内容或返回原语,则返回 newInstance。(通常构造函数不返回值,但它们可以选择这样做来覆盖正常的对象创建过程。)

只能使用 new 运算符实例化 - 尝试调用没有 new 的类将抛出 TypeError

¥Classes can only be instantiated with the new operator — attempting to call a class without new will throw a TypeError.

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

¥Creating an object with a user-defined constructor function requires two steps:

  1. 通过编写指定对象名称和属性的函数来定义对象类型。例如,创建对象 Foo 的构造函数可能如下所示:
    js
    function Foo(bar1, bar2) {
      this.bar1 = bar1;
      this.bar2 = bar2;
    }
    
  2. 使用 new 创建对象的实例。
    js
    const myFoo = new Foo("Bar 1", 2021);
    

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

¥Note: An object can have a property that is itself another object. See the examples below.

你始终可以向先前定义的对象实例添加属性。例如,语句 car1.color = "black" 将属性 color 添加到 car1,并为其分配值 "black"

¥You can always add a property to a previously defined object instance. For example, the statement car1.color = "black" adds a property color to car1, and assigns it a value of "black".

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

¥However, this does not affect any other objects. To add the new property to all objects of the same type, you must add the property to the constructor's prototype property. This defines a property that is shared by all objects created with that function, rather than by just one instance of the object type. The following code adds a color property with value "original color" to all objects of type Car, and then overwrites that value with the string "black" only in the instance object car1. For more information, see prototype.

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 的值也不同。

¥Note: While the constructor function can be invoked like any regular function (i.e. without the new operator), in this case a new object is not created and the value of this is also different.

函数可以通过检查 new.target 来知道它是否被 new 调用。当调用函数而没有 new 时,new.target 只有 undefined。例如,你可以拥有一个在调用时和构造时表现不同的函数:

¥A function can know whether it is invoked with new by checking new.target. new.target is only undefined when the function is invoked without new. For example, you can have a function that behaves differently when it's called versus when it's constructed:

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" }`

在引入 classes 的 ES6 之前,大多数 JavaScript 内置函数都是可调用和可构造的,尽管其中许多表现出不同的行为。仅举几例:

¥Prior to ES6, which introduced classes, most JavaScript built-ins are both callable and constructible, although many of them exhibit different behaviors. To name a few:

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

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

¥After ES6, the language is stricter about which are constructors and which are functions. For example:

  • 只能调用 Symbol()BigInt(),不能调用 new。尝试构造它们将抛出 TypeError
  • ProxyMap 只能与 new 一起构造。尝试调用它们将抛出 TypeError

示例

¥Examples

对象类型和对象实例

¥Object type and object instance

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

¥Suppose you want to create an object type for cars. You want this type of object to be called Car, and you want it to have properties for make, model, and year. To do this, you would write the following function:

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

现在你可以创建一个名为 myCar 的对象,如下所示:

¥Now you can create an object called myCar as follows:

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

该语句创建 myCar 并为其属性分配指定的值。那么 myCar.make 的值就是字符串 "鹰",myCar.year 就是整数 1993,依此类推。

¥This statement creates myCar and assigns it the specified values for its properties. Then the value of myCar.make is the string "Eagle", myCar.year is the integer 1993, and so on.

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

¥You can create any number of car objects by calls to new. For example:

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

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

¥Object property that is itself another object

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

¥Suppose you define an object called Person as follows:

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

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

¥And then instantiate two new Person objects as follows:

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

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

¥Then you can rewrite the definition of Car to include an owner property that takes a Person object, as follows:

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

要实例化新对象,请使用以下命令:

¥To instantiate the new objects, you then use the following:

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

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

¥Instead of passing a literal string or integer value when creating the new objects, the above statements pass the objects rand and ken as the parameters for the owners. To find out the name of the owner of car2, you can access the following property:

js
car2.owner.name;

new 与类一起使用

¥Using new with classes

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

规范

Specification
ECMAScript Language Specification
# sec-new-operator

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看