关于我发现MDN上new操作符有问题这件事

346 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

从来如此,便对么? —鲁迅

对比下MDN中英文下 new操作符

中文:

new 关键字的描述

image.png

英文:

new operator Description

developer.mozilla.org/en-US/docs/…

image.png

有什么区别呢?

可以看到,中文的翻译将function's prototype object直接翻译为 原型对象。

那这个prototype就是“原型”么?

其实不是,这里的 F.prototype 指的是 F 的一个名为 "prototype" 的常规属性。这听起来与“原型”这个术语很类似,但这里我们实际上指的是具有该名字的常规属性。

F.prototype

当我们用new F() 这样的构造函数来创建一个新对象。

如果 F.prototype 是一个对象,那么 new 操作符会使用它为新对象设置 [[Prototype]]

举例: 下面是一个例子:

let animal = {
  eats: true
};

function Rabbit(name) {
  this.name = name;
}

Rabbit.prototype = animal;

let rabbit = new Rabbit("White Rabbit"); //  rabbit.__proto__ == animal

alert( rabbit.eats ); // true

设置 Rabbit.prototype = animal 的字面意思是:“当创建了一个 new Rabbit 时,把它的 [[Prototype]] 赋值为 animal”。

image.png

注意:仅在new F被调用时才会为新对象的[[Prototype]]赋值,如果已经创建后又改变F.prototype,已经创建的对象[[Prototype]]不会改变。

默认的 F.prototype,构造器属性

每个函数都有"prototype"属性,不需要我们创建。 默认有一个属性:constructor对象,指向函数自身

如下:

function Rabbit() {}

/* default prototype
Rabbit.prototype = { constructor: Rabbit };
*/

通常,如果我们什么都不做,constructor 属性可以通过 [[Prototype]] 给所有 rabbits 使用:

function Rabbit() {}
// by default:
// Rabbit.prototype = { constructor: Rabbit }

let rabbit = new Rabbit(); // inherits from {constructor: Rabbit}

alert(rabbit.constructor == Rabbit); // true (from prototype)

image.png

关于 "constructor" 最重要的是

JavaScript 自身并不能确保正确的 "constructor" 函数值。

如果我们换掉了默认的"prototype",就不会有 "constructor" 了。

例如:

function Rabbit() {}
Rabbit.prototype = {
  jumps: true
};

let rabbit = new Rabbit();
alert(rabbit.constructor === Rabbit); // false

所以 为了保险 ,我们在"prototype"中添加新的属性,不要整体覆盖

function Rabbit() {}

// 不要将 Rabbit.prototype 整个覆盖
// 可以向其中添加内容
Rabbit.prototype.jumps = true
// 默认的 Rabbit.prototype.constructor 被保留了下来

或者手动创建constructor 属性。

总结

  • F.prototype 属性(不要把它与 [[Prototype]] 弄混了)在 new F 被调用时为新对象的 [[Prototype]] 赋值。
  • F.prototype 的值要么是一个对象,要么就是 null:其他值都不起作用。
  • "prototype" 属性仅在设置了一个构造函数(constructor function),并通过 new 调用时,才具有这种特殊的影响。

现在再理解一下new的描述:

  1. 创建一个空的简单JavaScript对象(即 {} );
  2. 为步骤1新创建的对象添加属性 __proto__ ,将该属性链接至构造函数的 prototype属性
  3. 将步骤1新创建的对象作为this的上下文 ;
  4. 如果该函数没有返回对象,则返回this