目录

🗻 JavaScript 原型构造

# F.prototype

JavaScript 中可以使用 new F() 这样的 构造器(构造函数)创建一个 新的对象

如果 F.prototype 是一个 对象,那么 new 操作符会使用它作为 新对象 设置 [[prototype]] 。(一个构造函数的原型,当使用构造函数创建一个新的对象时,对象的原型为这个构造函数的原型)

这里的 F.prototype 指的是 F 对象的一个名为 prototype常规属性

🌰 例子:

let animal = {
  eats: true
};

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

Rabbit.prototype = animal
let rabbit = new Rabbit("White Rabbit")

console.log(rabit.eats) // true
1
2
3
4
5
6
7
8
9
10
11
12

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

image-20220514122705502

"prototype" 是一个水平箭头,表示一个常规属性, [[Prototype]] 是垂直的,表示 rabbit 继承自 animal

提示

F.prototype 仅能用在 new F 时,它为新对象的 [[Prototype]] 赋值。

如果在创建之后, F.prototype 属性有了变化( F.prototype = <another object> ),那么通过 new F 创建的 新对象 也将随之拥有 新的对象 作为 [[Prototype]] ,但已经存在的对象将 保持旧有的值

如果在创建之后,修改 F.prototype 的值(修改引用),对已经存在的对象也会受到影响。

🌰 例子:

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

let rabbit = new Rabbit(); // 引用的是上面的prototyope

Rabbit.prototype = {
  eats: false
}

let rabbit2 = new Rabbit(); // 引用的是新的prototype
delete Rabbit.prototype.eats // 删除新定义的prototype的eats

console.log(rabbit.eats) // true
console.log(rabbit.eats) // undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 默认的 F.prototype

即便没有提供 prototype 给函数,每个函数都有 prototype 属性。默认的 prototype 是一个只有属性 constructor 的对象,属性 constructor 指向 函数自身

🌰 例子:

function Rabbit() {}

/* default prototype
Rabbit.prototype = { constructor: Rabbit };
*/
console.log(Rabbit.prototype.constructor === Rabbit) // true
1
2
3
4
5
6

image-20220514123046718

let rabbit = new Rabbit()
console.log(rabbit.constructor === Rabbit) // true
1
2

即便不显式操作, constructor 会通过 [[prototype]] 属性给所有的 rabbit (通过 new 创建的对象) 。

image-20220514123855757

🌰 例子 / 通过 constructor 创建一个新的对象,该对象使用 与对象相同的构造器

function Rabbit(name) {
  this.name = name
  console.log(name)
}

let rabbit = new Rabbit("White Rabbit") 
let rabbit2 = new rabbit.constructor("Black Rabit")
1
2
3
4
5
6
7

当有一个对象,但是 不知道它使用了哪一个构造器(来自第三方库的对象),如果想要创建另一个类似的对象,就可以是使用这种方法。

提示

注意:JavaScript 自身并不能确保正确的 constructor 的函数值。 它存在于函数的默认 prototype 中,但仅此而已。之后会发生什么 ,完全取决于使用人。

就是说,当把整个 默认的 prototype 替换掉,其中就不会有 constructor 了。

为了确保有正确的 prototype ,可以选择 添加 / 删除 属性到默认 prototype ,而不是整个将它 覆盖

🌰 例子:

function Rabbit() {}

Rabbit.prototype.jumps = true // 向 prototype 中添加属性
1
2
3

这样就可以将 默认的 prototype 保留下来。

或者 手动重新创建 constructor 属性,这样 constructor 也能被保留下来:

Rabbit.prototype = {
  jumps: true,
  constructor: Rabbit
};
1
2
3
4

# 总结

  • 通过构造函数,可以设置创建新的对象的 [[prototype]]

  • F.prototype 属性在 new F 被调用时为新对象的 [[Prototype]] 赋值。

  • F.prototype 的值要么是一个对象,要么就是 null 。其他值都不起作用。

  • F.prototype 属性仅在设置了一个构造函数,并通过 new 调用时,才具有这种特殊的影响。为了保留这个构造函数,应该在其之上添加属性,而不应该整个覆盖。

    可以通过这个构造函数创建类似的对象,但是如果 constructor 被重写了就不起作用。

📢 上次更新: 2022/09/02, 10:18:16