我们可以使用构造函数创建新对象,类似于 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__ 等于 animal
alert( 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() {}
/*
默认的 prototype
Rabbit.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