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
语法
参数
¥Parameters
constructor-
指定对象实例类型的类或函数。表达式可以是任何具有足够 precedence 的内容,包括标识符、属性访问权 或另一个
new表达式,但不允许使用 可选链接。 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:
- 创建一个空白的、纯 JavaScript 对象。为了方便起见,我们将其称为
newInstance。 - 如果
prototype是Object,则将newInstance的 [[Prototype]] 指向构造函数的prototype属性。否则,newInstance保持为普通对象,并以Object.prototype作为其 [[Prototype]]。注意:因此,从构造函数创建的所有实例都可以访问添加到构造函数的
prototype属性的属性/对象。¥Note: Properties/objects added to the constructor function's
prototypeproperty are therefore accessible to all instances created from the constructor function. - 使用给定参数执行构造函数,将
newInstance绑定为this上下文(即构造函数中对this的所有引用现在都引用newInstance)。 - 如果构造函数返回 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:
- 通过编写指定对象名称和属性的函数来定义对象类型。例如,创建对象
Foo的构造函数可能如下所示:jsfunction Foo(bar1, bar2) { this.bar1 = bar1; this.bar2 = bar2; } - 使用
new创建对象的实例。jsconst 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.
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
newoperator), in this case a new object is not created and the value ofthisis 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:
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:
示例
对象类型和对象实例
¥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:
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:
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:
const kensCar = new Car("Nissan", "300ZX", 1992);
对象属性本身就是另一个对象
¥Object property that is itself another object
假设你定义了一个名为 Person 的对象,如下所示:
¥Suppose you define an object called Person as follows:
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
然后实例化两个新的 Person 对象如下:
¥And then instantiate two new Person objects as follows:
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:
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:
const car1 = new Car("Eagle", "Talon TSi", 1993, rand);
const car2 = new Car("Nissan", "300ZX", 1992, ken);
上述语句在创建新对象时没有传递文字字符串或整数值,而是将对象 rand 和 ken 作为所有者的参数传递。要查找 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:
car2.owner.name;
将 new 与类一起使用
规范
| Specification |
|---|
| ECMAScript Language Specification # sec-new-operator |
浏览器兼容性
BCD tables only load in the browser
也可以看看
¥See also