ECMAScript (JavaScript) 支持“基于原型的继承”。这意味着 JS 中的“类”和“实例”之间没有区别。相对于其他语言的 OOP,在 JS 中“类”和“实例”基本上是一回事:
当您定义Bla
时,它会立即实例化(准备好使用),但也可以用作“原型”来克隆object Bla
具有相同属性和方法的另一个实例的初始(!)定义。
在 ECMAScript 中,一切都是对象,即使是对象的初始定义。在其他 OOP 语言中,定义部分有一个“类”。
该prototype
对象适用于您想要在初始定义之后扩展“Bla”的原型(阅读:类“Bla”)并将新属性/函数添加到所有当前和未来实例的情况Bla
。
如果您现在感到困惑,我认为此代码示例可能有助于发现差异:
// when defining "Bla", the initial definition is copied into the "prototype"
var Bla = function()
{
this.a = 1;
}
// we can either modify the "prototype" of "Bla"
Bla.prototype.b = 2;
// or we can modify the instance of "Bla"
Bla.c = 3;
// now lets experiment with this..
var x = new Bla(); // read: "clone the prototype of 'Bla' into variable 'x'"
console.log(x.b); // logs "2" -- "b" was added to the prototype, available to all instances
console.log(x.c); // undefined -- "c" only exists in the instance "Bla"
console.log(Bla.c); // logs "3" -- "Bla" is an object, just like our new instance 'x'
// also note this:
Bla.a = 1337;
var y = new Bla();
console.log(y.a); // logs "1" -- because the "prototype" was cloned,
// opposed to the current state of object "Bla"
console.log(Bla.a); // logs "1337"
正如您在最后一个示例中看到的,“原型”的概念对于避免克隆对象的当前“状态”是必要的。
如果不以这种方式实现,您可能会得到奇怪的效果,因为如果在克隆之前使用/修改了原始对象“Bla”,那么当前状态也会被复制。这就是语言设计者选择prototype
构造的原因。
永远记住:“Bla”不是静态定义,就像“类”在其他 OOP 语言中一样。
ECMAScriptprototype
规范说:
原型是用于在 ECMAScript 中实现结构、状态和行为继承的对象。当构造函数创建一个对象时,该对象隐式引用构造函数的关联原型,以解析属性引用。构造函数的关联原型可以由程序表达式constructor.prototype引用,并且添加到对象原型的属性通过继承由共享原型的所有对象共享。
一些 JS 框架,例如同名的“原型”,大量使用此功能来扩展 Javascript 内置对象的功能。
例如,它array
使用方法扩展原生对象forEach
,将这个缺失的特性添加到 JS:
Array.prototype.forEach = function each(iterator, context) {
for (var i = 0, length = this.length >>> 0; i < length; i++) {
if (i in this) iterator.call(context, this[i], i, this);
}
}