描述
当一个函数使用 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 类型的对象添加一个值为 "original color" 的 color 属性,然后仅在实例对象 car1 中将其值覆盖为字符串 "black"。有关更多信息,请参阅原型。
jsfunction 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。例如,你可以有一个函数,它在被调用时和被构造时表现不同:
jsfunction 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。
Proxy 和 Map 只能用 new 构造。尝试调用它们将抛出 TypeError。
西甲联赛直播全攻略:最佳观看平台与回放资源一览
世足/阿根廷恐遭禁賽?賽後舉政治標語 FIFA要查了