🗻 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
2
3
4
5
6
7
8
9
10
11
12
设置
Rabbit.prototype = animal
的字面意思是:创建一个new Rabbit
时,把它的[[[prototype]]]
赋值为animal
。
"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
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
2
3
4
5
6
let rabbit = new Rabbit()
console.log(rabbit.constructor === Rabbit) // true
2
即便不显式操作,
constructor
会通过[[prototype]]
属性给所有的rabbit
(通过new
创建的对象) 。
🌰 例子 / 通过 constructor
创建一个新的对象,该对象使用 与对象相同的构造器:
function Rabbit(name) {
this.name = name
console.log(name)
}
let rabbit = new Rabbit("White Rabbit")
let rabbit2 = new rabbit.constructor("Black Rabit")
2
3
4
5
6
7
当有一个对象,但是 不知道它使用了哪一个构造器(来自第三方库的对象),如果想要创建另一个类似的对象,就可以是使用这种方法。
提示
注意:JavaScript 自身并不能确保正确的 constructor
的函数值。 它存在于函数的默认 prototype
中,但仅此而已。之后会发生什么 ,完全取决于使用人。
就是说,当把整个 默认的 prototype
替换掉,其中就不会有 constructor
了。
为了确保有正确的 prototype
,可以选择 添加 / 删除 属性到默认 prototype
,而不是整个将它 覆盖。
🌰 例子:
function Rabbit() {}
Rabbit.prototype.jumps = true // 向 prototype 中添加属性
2
3
这样就可以将 默认的 prototype
保留下来。
或者 手动重新创建 constructor
属性,这样 constructor
也能被保留下来:
Rabbit.prototype = {
jumps: true,
constructor: Rabbit
};
2
3
4
# 总结
通过构造函数,可以设置创建新的对象的
[[prototype]]
。F.prototype
属性在new F
被调用时为新对象的[[Prototype]]
赋值。F.prototype
的值要么是一个对象,要么就是null
。其他值都不起作用。F.prototype
属性仅在设置了一个构造函数,并通过new
调用时,才具有这种特殊的影响。为了保留这个构造函数,应该在其之上添加属性,而不应该整个覆盖。可以通过这个构造函数创建类似的对象,但是如果
constructor
被重写了就不起作用。