🗻 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被重写了就不起作用。



