Javascript中的原型

cor*_*zza 4 javascript oop prototype prototypal-inheritance

在原型语言中,对象基本上可以互相克隆.

所以,假设我们有一个构造函数:

Bla = function()
{
    this.a = 1;
}
Run Code Online (Sandbox Code Playgroud)

我可以像这样创建该对象的新实例:x = new Bla();.现在,x.a返回1.

如果我要写Bla.prototype.b = 2,那么x.b会返回2.但是,为什么?如果x"克隆"了Bla,为什么我不能这么说Bla.b = 2,没有引用Bla.prototype,仍然可以获得相同的功能?这与this关键字有关吗?

Kai*_*aii 10

ECMAScript(JavaScript)支持"基于原型的继承".这意味着JS中的"class"和"instance"之间没有区别.与其他语言的OOP相反,在JS中,"类"和"实例"基本相同:

当您定义"Bla"时,它会立即实例化(准备使用),但也可以作为"原型"来克隆具有相同属性和方法的另一个实例的对象"Bla"的初始定义(!).在其他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'"  
alert(x.b);     // alerts "2"  -- "b" was added to the prototype, available to all instances

alert(x.c);     // undefined   -- "c" only exists in the instance "Bla"
alert(Bla.c);   // alerts "3"  -- "Bla" is an object, just like our new instance 'x'

// also note this:
Bla.a = 1337;
var y = new Bla();
alert(y.a);     // alerts "1"  -- because the initial definition was cloned, 
                // opposed to the current state of object "Bla"
alert(Bla.a);   // alerts "1337" 
Run Code Online (Sandbox Code Playgroud)

正如您在上一个示例中所看到的,"原型"的概念对于避免克隆对象的当前"状态"是必要的.

如果它不会以这种方式实现,你可能会得到奇怪的效果,因为如果在克隆它之前使用/修改了原始对象"Bla",那么当前状态也将被复制.这就是为什么设计师选择了这个prototype结构.

永远记住:"Bla"不是静态定义,就像其他OOP语言中的"类"一样.


ECMAScript规范说,有关prototype:

原型是用于在ECMAScript中实现结构,状态和行为继承的对象.当构造函数创建对象时,该对象隐式引用构造函数的关联原型以解析属性引用.构造函数的关联原型可以由程序表达式constructor.prototype引用,添加到对象原型的属性通过继承由共享原型的所有对象共享.

所有JS框架,如同名的" 原型 "或jQuery都大量使用此功能来扩展Javascripts内置对象的功能.

例如,JS框架" prototype " 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);
  }
}
Run Code Online (Sandbox Code Playgroud)