深入理解JavaScript系列(10) JavaScript核心(晋级高手

适合的读者:有经验的开发员,专业前端人员。

原作者: Dmitry A. Soshnikov
发布时间: 2010-09-02
原文:
参考1:?p=2795
参考2:
主要是综合了上面2位高手的中文翻译,将两篇文章的精华部分都结合在一起了。

我们首先来看一下对象[Object]的概念,这也是ECMASript中最基本的概念。

对象Object
ECMAScript是一门高度抽象的面向对象(object-oriented)语言,用以处理Objects对象. 当然,也有基本类型,但是必要时,也需要转换成object对象来用。

An object is a collection of properties and has a single prototype object. The prototype may be either an object or the null value.

Object是一个属性的集合,并且都拥有一个单独的原型对象[prototype object]. 这个原型对象[prototype object]可以是一个object或者null值。
复制代码
让我们来举一个基本Object的例子,首先我们要清楚,一个Object的prototype是一个内部的[[prototype]]属性的引用。

不过一般来说,我们会使用__<内部属性名>__ 下划线来代替双括号,例如__proto__(这是某些脚本引擎比如SpiderMonkey的对于原型概念的具体实现,尽管并非标准)。

复制代码 代码如下:


var foo = {
x: 10,
y: 20
};


上述代码foo对象有两个显式的属性[explicit own properties]和一个自带隐式的 __proto__ 属性[implicit __proto__ property],指向foo的原型。

深入理解JavaScript系列(10) JavaScript核心(晋级高手

图 1. 一个含有原型的基本对象

为什么需要原型呢,让我们考虑 原型链 的概念来回答这个问题。
原型链(Prototype chain)
原型对象也是普通的对象,并且也有可能有自己的原型,如果一个原型对象的原型不为null的话,我们就称之为原型链(prototype chain)。

A prototype chain is a finite chain of objects which is used to implemented inheritance and shared properties.原型链是一个由对象组成的有限对象链由于实现继承和共享属性。 

想象一个这种情况,2个对象,大部分内容都一样,只有一小部分不一样,很明显,在一个好的设计模式中,我们会需要重用那部分相同的,而不是在每个对象中重复定义那些相同的方法或者属性。在基于类[class-based]的系统中,这些重用部分被称为类的继承 – 相同的部分放入class A,然后class B和class C从A继承,并且可以声明拥有各自的独特的东西。

ECMAScript没有类的概念。但是,重用[reuse]这个理念没什么不同(某些方面,甚至比class-更加灵活),可以由prototype chain原型链来实现。这种继承被称为delegation based inheritance-基于继承的委托,或者更通俗一些,叫做原型继承。

类似于类”A”,”B”,”C”,在ECMAScript中尼创建对象类”a”,”b”,”c”,相应地, 对象“a” 拥有对象“b”和”c”的共同部分。同时对象“b”和”c”只包含它们自己的附加属性或方法。 

复制代码 代码如下:


var a = { x: 10, calculate: function (z) { return this.x + this.y + z }}; var b = { y: 20, __proto__: a}; var c = { y: 30, __proto__: a}; // 调用继承过来的方法b.calculate(30); // 60c.calculate(40); // 80


这样看上去是不是很简单啦。b和c可以使用a中定义的calculate方法,这就是有原型链来[prototype chain]实现的。

原理很简单:如果在对象b中找不到calculate方法(也就是对象b中没有这个calculate属性), 那么就会沿着原型链开始找。如果这个calculate方法在b的prototype中没有找到,那么就会沿着原型链找到a的prototype,一直遍历完整个原型链。记住,一旦找到,就返回第一个找到的属性或者方法。因此,第一个找到的属性成为继承属性。如果遍历完整个原型链,仍然没有找到,那么就会返回undefined。

注意一点,this这个值在一个继承机制中,仍然是指向它原本属于的对象,而不是从原型链上找到它时,它所属于的对象。例如,以上的例子,this.y是从b和c中获取的,而不是a。当然,你也发现了this.x是从a取的,因为是通过原型链机制找到的。

如果一个对象的prototype没有显示的声明过或定义过,那么__prototype__的默认值就是object.prototype, 而object.prototype也会有一个__prototype__, 这个就是原型链的终点了,被设置为null。

下面的图示就是表示了上述a,b,c的继承关系

深入理解JavaScript系列(10) JavaScript核心(晋级高手

图 2. 原型链

原型链通常将会在这样的情况下使用:对象拥有 相同或相似的状态结构(same or similar state structure) (即相同的属性集合)与 不同的状态值(different state values)。在这种情况下,我们可以使用 构造函数(Constructor) 在 特定模式(specified pattern) 下创建对象。
构造函数(Constructor)
除了创建对象,构造函数(constructor) 还做了另一件有用的事情—自动为创建的新对象设置了原型对象(prototype object) 。原型对象存放于 ConstructorFunction.prototype 属性中。

例如,我们重写之前例子,使用构造函数创建对象“b”和“c”,那么对象”a”则扮演了“Foo.prototype”这个角色:

复制代码 代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdjdxs.html