Javascript Prototypes之旅(A Plain English Guide to JavaScript Prototypes译文)

英文原文地址:http://sporto.github.com/blog/2013/02/22/a-plain-english-guide-to-javascript-prototypes/?utm_source=javascriptweekly&utm_medium=email

  当我第一次学习Javascript的对象模型时,我的反应时困惑。因为这是我第一次接触基于原型的语言,所以我完完全全被原型弄得糊里糊涂(译者语:在看这篇文章前,我一直困惑function的prototype和object的__proto__的区别及它们之间的关系)。我不能理解JavaScript通过构造函数(function constructors)的方式来实现一种独特的原型。我相信你们当中也有类似经历的人。

  但随着自己写得越来越多javascript,我不仅理解了它的对象模型而且已经开始喜欢上它了。感谢Javascript我发现基于原型的语言的高雅与灵活。我现在十分喜欢基于原型的语言,因为它有比基于类的语言更简单和灵活的对性模型。

1. Prototypes in Javascript

  大多数教程多会在直接通过讲述构造函数(constructor functions)来讲解Javascript的对象。我并不认同这种做法,这样只会令到我们更困惑。所以下面我们先学习一些基础的原型吧!

2. Prototype chains(prototype inheritance)原型链/原型继承

  Javascript的每个对象均有一个原型(prototype)。当消息(请求某个属性的指令)到达某个对象时,Javascript会尝试在该对象上寻找该属性,但没有的时候就会将消息转发到该对象的原型并在原型上寻找该属性,就是这样不断向上层原型转发消息,直到在某个原型中找到该属性或消息转发到顶层原型(Object对象)。(译者语:每个对象的原型均指向另一个对象,最顶层的原型就是Object类的实例)

  

原型继承链可以无限延长。但一般情况下过长的原型链会令人困惑且难以维护。

 

3.The __proto__ object

  我们可以通过__proto__属性来简化对Javascript原型的理解。但不幸的是__proto__属性并非Javascript的标准接口。所以我们不应该在生产环境中依赖该属性。我看一看下面的代码片段吧!

可以看到通过对象的__proto__属性我们可以简单、方便地设置对象的原型。

下面我们通过isPrototypeof函数来判断父、子类的关系

 

4. Prototype lookups are dynamic(原型变化的即时性)

  你可以在任何时间添加属性到对象的原型中,然后就能马上通过对象来获取该属性。(译者语:因为正如2. Prototype chains(prototype inheritance)原型链/原型继承讲述那样,消息是在原型链传递并在原型中寻找该属性,所以为原型增删改了属性能即时反映出来)

 

5. New/updated properties are assigned to the  object, not to the prototype(增改对象的属性)

  看代码吧!

(译者语:在对象中已找到了相应的属性,那么就不会将消息转发到原型去)

 

6. Object.create

  前面已经说过__proto__属性并非设置原型的标准方法。下面我们使用Object.create方法来创建对象并指定该对象的原型。该方法在ES5中可用,但老的浏览器和JS引擎要通过es5-hhim来使用了。

(译者语:我们甚至可以通过object.create(null)开创建一个没有原型的对象;而使用其他方式创建的对象它的原型链中至少有一个Object类实例)

当然在创建对象的时候,还可以设置该对象的属性。

这里打算展开对象属性设置方面的几个特性的使用方法,大家可以参考相关的文档 here

7. Object.getProtype

  我们可以通过Object.getPrototypeOf来获取对象的原型

8.Constructor Functions(构造函数)

  构造函是javascript中用于构造原型链的最常用的方法。因为它是构造类型的唯一的原始方式。而很对javascript引擎对构造函数也提供了性能上的优化。

  与此同时,构造函数是javascript中一个重要且容易令人疑惑的知识点。

8.1. Functions as contructors

  

我们通过关键字new来创建Foo函数的实例foo

8.2. 'this' is assigned implicitly(隐式分配的this)

  当我们使用关键字new创建函数实例时,Javascript会隐式地创建一个this对象,并在函数的最后返回该this对象。

相当于

注意:这个隐式创建的this对象,当且仅当使用关键字new创建函数实例时出现,若不使用关键字new就会就会出现不可预知的问题,一般情况下为以首字母大写的方式来命名构造函数,以提示需使用关键字new来调用该函数。

8.3. The 'function prototype'

  每一个Javascript的函数都有一个名为prototype的属性(译者语:这个prototype属性与之前说__proto__一样会指向原型,它们之间的关系下面的内容会有所讲解。因为prototype这个属性名称的中文就是为原型,所以为了区分下面的内容会用“prototype属性”来代表function的prototype属性)

这个prototype属性与之前说__proto__一样会指向原型,但两者指向的原型又有所区别,具体请看

(译者语:这里原文的代码和讲解有问题,据本人实践所得,对象并没有prototype属性,若要访问对象的原型需要使用__proto__属性或Object.getPrototype函数;而要访问函数的原型则要通过访问prototype属性。而上述代码的无论foo是对象还是函数均有一方必为undefined,比较结果铁定为false。下面代码片段可以证明两者指向相同的原型:

  function Foo(){}

  var foo = new Foo();

  Object.getPrototype(foo) === Foo.prototype; // => true

  且原型为Foo {},该原型的原型为Object {};Foo{} 中有constructor属性指向function Foo(){}自身。)

__proto__和prototype属性的关系其实很简单,prototype属性所指向的原型会在使用关键字new调用构造函数时被复制到隐式创建的this对象的__proto__中。所以prototype属性指向的原型有那些属性和方法,那么__proto__就有哪些属性和方法。

我想大家应该已经理解了吧,转载请标明出处:http://www.cnblogs.com/fsjohnhuang/archive/2013/03/04/2942274.html^_^!!

posted @ 2013-03-04 09:34  ^_^肥仔John  阅读(1393)  评论(7编辑  收藏  举报