new
**new
** 运算符允许开发人员创建用户定义的对象类型的实例,或创建具有构造函数的内置对象类型的实例。
试一试
语法
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
将执行以下操作
- 创建一个空白的、普通的 JavaScript 对象。为了方便起见,我们称之为
newInstance
。 - 如果
prototype
是一个Object
,则将newInstance
的 [[Prototype]] 指向构造函数的prototype
属性。否则,newInstance
将保留为一个普通的对象,其 [[Prototype]] 为Object.prototype
。注意:添加到构造函数的
prototype
属性的属性/对象因此可供从构造函数创建的所有实例访问。 - 使用给定参数执行构造函数,将
newInstance
绑定为this
上下文(即,构造函数中对this
的所有引用现在都引用newInstance
)。 - 如果构造函数返回一个非原始类型,则此返回值将成为整个
new
表达式的结果。否则,如果构造函数没有返回值或返回原始类型,则将返回newInstance
。(通常构造函数不会返回值,但它们可以选择这样做以覆盖正常的对象创建过程。)
类只能使用 new
运算符实例化 - 尝试在没有 new
的情况下调用类将抛出 TypeError
。
使用用户定义的构造函数创建对象需要两个步骤
- 通过编写一个指定其名称和属性的函数来定义对象类型。例如,用于创建对象
Foo
的构造函数可能如下所示jsfunction Foo(bar1, bar2) { this.bar1 = bar1; this.bar2 = bar2; }
- 使用
new
创建对象的实例。jsconst myFoo = new Foo("Bar 1", 2021);
注意:对象可以有一个属性,该属性本身是另一个对象。请参阅下面的示例。
您始终可以向先前定义的对象实例添加属性。例如,语句 car1.color = "black"
向 car1
添加了一个名为 color
的属性,并为其分配了值 "black"
。
但是,这不会影响任何其他对象。要将新属性添加到所有相同类型的对象,您必须将该属性添加到构造函数的 prototype
属性。这定义了一个由使用该函数创建的所有对象共享的属性,而不是仅由对象类型的一个实例共享。以下代码向所有类型为 Car
的对象添加了一个名为 color
的属性,其值为 "original color"
,然后仅在实例对象 car1
中将该值覆盖为字符串 "black"
。有关更多信息,请参阅原型。
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.target
仅在没有 new
调用函数时为 undefined
。例如,您可以创建一个函数,当它被调用时与被构造时表现不同
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 之后,语言对哪些是构造函数哪些是函数更加严格。例如
示例
对象类型和对象实例
假设您想为汽车创建一种对象类型。您希望这种类型的对象被称为 Car
,并且希望它具有品牌、型号和年份的属性。为此,您将编写以下函数
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
现在,您可以创建名为 myCar
的对象,如下所示
const myCar = new Car("Eagle", "Talon TSi", 1993);
此语句创建 myCar
并为其属性分配指定的值。然后,myCar.make
的值为字符串 "Eagle",myCar.year
为整数 1993,等等。
您可以通过调用 new
创建任意数量的 car
对象。例如
const kensCar = new Car("Nissan", "300ZX", 1992);
本身是另一个对象的属性
假设您定义了一个名为 Person
的对象,如下所示
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
然后实例化两个新的 Person
对象,如下所示
const rand = new Person("Rand McNally", 33, "M");
const ken = new Person("Ken Jones", 39, "M");
然后,您可以重写 Car
的定义以包含一个名为 owner
的属性,该属性接受一个 Person
对象,如下所示
function Car(make, model, year, owner) {
this.make = make;
this.model = model;
this.year = year;
this.owner = owner;
}
要实例化新对象,您将使用以下方法
const car1 = new Car("Eagle", "Talon TSi", 1993, rand);
const car2 = new Car("Nissan", "300ZX", 1992, ken);
在创建新对象时,不是传递文字字符串或整数,上面的语句将对象 rand
和 ken
作为参数传递给所有者。要找出 car2
所有者的姓名,您可以访问以下属性
car2.owner.name;
在类中使用 new
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 语言规范 # sec-new-operator |
浏览器兼容性
BCD 表格仅在浏览器中加载