记住,可以使用构造函数创建新对象,例如 new F()
。
如果 F.prototype
是一个对象,则 new
运算符使用它为新对象设置 [[Prototype]]
。
JavaScript 从一开始就有原型继承。它是该语言的核心特性之一。
但在过去,无法直接访问它。唯一可靠的方法是构造函数的 "prototype"
属性,如本章所述。因此,许多脚本仍然使用它。
请注意,这里的 F.prototype
表示 F
上名为 "prototype"
的常规属性。它听起来与术语“原型”有些相似,但这里我们真正指的是带有此名称的常规属性。
以下是示例
let animal = {
eats: true
};
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype = animal;
let rabbit = new Rabbit("White 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
属性发生更改(F.prototype = <another object>
),那么由 new F
创建的新对象将具有另一个对象作为 [[Prototype]]
,但已存在的对象将保留旧对象。
默认 F.prototype,构造函数属性
即使我们不提供,每个函数都具有 “prototype”
属性。
默认 “prototype”
是一个对象,它具有唯一属性 constructor
,该属性指向函数本身。
类似于此
function Rabbit() {}
/* default prototype
Rabbit.prototype = { constructor: Rabbit };
*/
我们可以检查它
function Rabbit() {}
// by default:
// Rabbit.prototype = { constructor: Rabbit }
alert( Rabbit.prototype.constructor == Rabbit ); // true
当然,如果我们不执行任何操作,则所有兔子都可以通过 [[Prototype]]
使用 constructor
属性
function Rabbit() {}
// by default:
// Rabbit.prototype = { constructor: Rabbit }
let rabbit = new Rabbit(); // inherits from {constructor: Rabbit}
alert(rabbit.constructor == Rabbit); // true (from prototype)
我们可以使用 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();
alert(rabbit.constructor === Rabbit); // false
因此,为了保持正确的 “constructor”
,我们可以选择向默认 “prototype”
添加/删除属性,而不是整体覆盖它
function Rabbit() {}
// Not overwrite Rabbit.prototype totally
// just add to it
Rabbit.prototype.jumps = true
// the default Rabbit.prototype.constructor is preserved
或者,也可以手动重新创建 constructor
属性
Rabbit.prototype = {
jumps: true,
constructor: Rabbit
};
// now constructor is also correct, because we added it
摘要
在本章中,我们简要介绍了通过构造函数创建对象时设置 [[Prototype]]
的方法。稍后,我们将看到更多依赖于它的高级编程模式。
一切都非常简单,只需几个注释即可阐明问题
F.prototype
属性(不要误认为是[[Prototype]]
)在调用new F()
时设置新对象的[[Prototype]]
。F.prototype
的值应该是对象或null
:其他值不起作用。- 只有在构造函数上设置时,
"prototype"
属性才具有这种特殊效果,并使用new
调用。
在普通对象上,prototype
没什么特别之处
let user = {
name: "John",
prototype: "Bla-bla" // no magic at all
};
默认情况下,所有函数都有 F.prototype = { constructor: F }
,因此我们可以通过访问其 "constructor"
属性来获取对象的构造函数。
评论
<code>
标记,对于多行代码 – 将它们包装在<pre>
标记中,对于 10 行以上的代码 – 使用沙盒(plnkr,jsbin,codepen…)