我们可以使用构造函数创建新对象,类似于 new F() 这种方式。
如果 F.prototype 的值是个对象,那么 new 操作符就会使用这个对象作为新建对象的 [[Prototype]] 值。
注意:
原型继承是 JavaScript 这么语言的核心特性。
在以前,没有可以直接访问对象原型的方法。唯一可靠的方式是通过构造函数的 “
prototype”属性。现在还有许多脚本在这样做。
注意这里的 F.prototype 表示 F 上的一个叫“prototype”的属性。注意与之前说的名词“prototype(原型)”区分开。
下面举个例子:
let animal = {eats: true};function Rabbit(name) {this.name = name;}Rabbit.prototype = animal;let rabbit = new Rabbit('小白兔'); // rabbit.__proto__ 等于 animalalert( rabbit.eats ); // true
Rabbit.prototype = animal 这句话表示“在用 new Rabbit 创建一个兔子的时候,让它的 [[Prototype]] 属性赋值为 animal”。
下面是结构说明:

图片里,“prototype”是个横向箭头,表明是个常规属性,[[Prototype]] 是垂直的,表示 rabbit 继承自 animal。
注意:
**F.prototype**仅在**new F**时被使用
F.prototype仅在用new F形式调用时被使用,被用来赋值给新对象的[[Prototype]]属性。之后新对象与F.prototype之间再无联络。可以把它想象成是“one-time gift(一次性礼物)”。如果使用
**F**创建完一个对象后,改变F.prototype属性值(F.prototype = <another object>),那之后再用new F方式创建的新对象的[[Prototype]]属性值就是另一个对象了,之前已创建对象的[[Prototype]]属性保持原样。
默认的 F.prototype、constructor 属性
即使我们没有显式指定,每个函数都会有一个“prototype”属性。
默认的“prototype”属性是一个对象,仅包含唯一属性 constructor,这个属性的属性值又指向函数本身。
举个例子:
function Rabbit() {}/*默认的 prototypeRabbit.prototype = { constructor: Rabbit };*/

我们试下:
function Rabbit() {}// 默认// Rabbit.prototype = { contructor: Rabbit };alert( Rabbit.prototype.constructor === Rabbit ); // true
正常来说,如果我们什么都不做,所有的兔子(即 Rabbit 实例)都能通过 [[Prototype]] 访问 constructor 属性:
function Rabbit() {}// 默认// Rabbit.prototype = { contructor: Rabbit };let rabbit = new Rabbit(); // 继承自 {constructor: Rabbit}alert( rabbit.constructor === Rabbit ); // true(从原型中获得)

我们可以使用 constructor 属性来创建一个新对象,本质上使用的就是同一个构造函数。
看下面:
function Rabbit(name) {this.name = name;alert(name);}let rabbit = new Rabbit('White Rabbit');let rabbit2 = new rabbit.constructor('Black Rabbit')
当我们已有一个对象时,在不知道它是用哪个构造函数创建的情况下(例如,它来自于第三方库),使用这种方式创建另一个同类对象。
但使用“constructor”一个问题是:JavaScript 并不能保证“constructor”值一定是正确的。
是,它默认是在函数的“prototype”属性里,但仅此而已。之后会发生什么,则完全取决于我们。
特别地,如果我们把默认的原型对象整个替换了,那么也就不会有这个“constructor”属性了。
function Rabbit() {}Rabbit.prototype = {jumps: true};let rabbit = new Rabbit();console.log(rabbit.constructor === Rabbit); // false
所以,为了确保正确的“constructor”,我们可以直接操作默认的“prototype”属性,为这个对象添加/删除属性,而不是重写它:
function Rabbit() {}// 不要重写 Rabbit.prototype// 只是在其基础上添加Rabbit.prototype.jumps = true// 这样,默认的 Rabbit.prototype.constructor 就还在
或者,手动添加 constructor 属性也行:
Rabbit.prototype = {jumps: true,constructor: Rabbit};// 现在,constructor 属性也是正确的,因为我们手动添加了
总结
本章简要叙述了,为使用构造函数创建的对象设置 [[Prototype]] 的方法,后面我们将看到更高级的、依赖于它的编程模式。
本篇没有太复杂的内容,我们简单做下总结:
F.prototype仅在用new F形式调用时被使用,被用来赋值给新对象的[[Prototype]]属性。F.prototype的值可能是个对象,也可以为null。赋值其它类型值无效。- “
prototype”属性仅用在构造函数上使,才有如此特殊的效果,并且还要搭配new运算符来使用。
常规对象的 prototype 属性没有任何特别之处:
let user = {name: 'John',prototype: 'Bla-bla' // 没有任何特别之处};
所有函数默认都有 F.prototype = { constructor: F },我们可以通过对象的“constructor”属性获得这个对象在创建时使用的构造函数。
(完)
📄 文档信息
🕘 更新时间:2020/01/14
🔗 原文链接:http://javascript.info/function-prototype
