JavaScript基础知识(一) Prototype Chain

    前些天学习《JavaScript设计模式》(这是一本非常好的书,翻译这本书的作者也很负责,翻译的很好)。其中在介绍JavaScript中如何模拟接口,如何模拟面向对象中的类做了很详尽的解释。但是在学习途中遇到了很多基础知识没有理解,准备用几个章节介绍这些天对这些基础知识学习。最难懂荷花时间最长的就是对JavaScript中Prototype的理解。手头有我从网上搜集的各种资料,在这里贴出百度云的链接,希望想学习的朋友下载学习下。我都整理成PDF格式了。

  1. 链接:http://pan.baidu.com/share/link?shareid=3816985477&uk=2869009987 密码:dwh4

在介绍Prototype之前先说一个背景知识,ECMA-262-3是javascript的一个规范,各个浏览器厂商都是根据这个ECMA规范定制的javascript功能。ECMAScript就是实现了ECMA-262-3协议的javascript。也就是我们通常所说的javascript。

在这一个章节中,我将总结有关Prototype Chain,对象是如何创建出来的以及Function于Object的关系等基础知识。

文中使用的是V8引擎的Nodejs调试的,如果没有学习过node的同学,可以直接嵌套在HTML中,使用aler()方法查看输出,需要指出的是,__proto__在火狐浏览器种才能调用,其他的调用会出错的。

在讲Prototype之前得先说一下背景知识:

Object

Object.prototype是所有对象的祖先(规则一),Object是Javascript的内置函数。在Javascript中,所有的对象都是字典型结构,也就是说,不管对象多么复杂,都可以用JSON来创建并复制。

  1. //创建一个没有属性的对象
  2. var obj = {};
  3. //创建一个有属性的对象
  4. var obj_1 = {name:"angle",age:18,married:false};
  5. //创建有属性,有方法的对象
  6. var obj_2 = {text:"Hello World",say:function(){console.log(this.text)}}

Function

Function.prototype是所有函数的原型(规则二),包括构造函数。同Object一样,都是javascript的内置函数。在Javascript中的代码只有function一种形式,我们在写一个function test(){}的时候,只不过是建立了一个function类型的实体。

  1. function Abd(){
  2.   this.a = 1;
  3. }
  4. console.log(typeof Abd);

输出结果 function。

所有的function都有显示的原型和隐性的原型,即__proto__和prototype

Prototype

在Javascript中有两种形式的原型,一种是隐性的原型 __proto__,另一种是显性的原型 Prototype。我们自定义的方法,

但是对象只存在隐性原型

  1. function Abd(){
  2.   this.a = 1;
  3. }
  4. var a1 = new Abd();
  5. console.log(a1.prototype);

输出结果是:undefined

在javascript中,new关键字创建对象的过程

    1à建立一个新的对象。

    2à将对象内置的原型对象(__proto__)指向其构造函数的Prototype

    3à将该对象作为this参数调用构造函数,完成成员变量等的初始化工作

在第二步中表明了,所有对象的__proto__都指向了其构造函数的Prototype(规则三),即ABd.prototype

其实在第三部中隐含了一个过程。即所有对象的constructor都指向当前对象的构造函数

  1. console.log(a1.constructor === Abd);//输出结果为true

然而每一个函数(function类型)都有一个默认属性,即prototype,这个prototype.constructor指向这个函数(规则四)。看似绕了一个圈圈。

基本的知识已经介绍完了,我们使用《nodejs开发指南中》讲原型链中的例子,结合图片理解:

  1. function Foo(){
  2. }
  3. var obj = new Object();
  4. var foo = new Foo();

途中虽然交替穿插着很多箭头,看起来很杂乱,其实只不过是根据上面所说的四条规则索引而已

    à上图中1处为构造出来的对象。他只有隐性的原型,并且原型指向其构造函数的Prototype

    à图中2出可以这么理解,因为function的原型指向的是一个对象,所以这里2处其实就是Foo.prototype。并且Foo.prototype的构造函数constructor指向Foo。同理Foo的__proto__指向其构造函数的原型Function.prototype。因为所有的函数都是Function类型的,Function.prototype的构造函数指向Function(规则三于规则四

    àObject也是一函数。这里就要注意一下了。Object.prototype是没有原型的,所以也是上面的规则一

    à从图中4出可以看出,所有的函数的原型的根都是Function.prototype。这一点符合规则二

Prototype Chain

所谓prototype chain(原型链),从上图中可以看出各种杂乱的箭头指向。原型链就是根据Prototype指向的连接。Javascript中对象的继承使用的就是prototype。当然想要使用javascript实现继承还需要做很多包装。这里只是简单的说明原型链的工作原理:

  1. function Sub(){
  2.   this.a = "haha";
  3.   this.b = 5;
  4. }
  5. Sub.prototype.c = function(){//往Sub的原型中添加方法c
  6.   console.log("prototype method");
  7. };
  8. Sub.prototype.d = 6;//往Sub的原型中添加属性d
  9. var testSub = new Sub();
  10. console.log(testSub.a);
  11. console.log(testSub.b);
  12. testSub.c();
  13. console.log(testSub.d);

输出结果:

从结果中可以看出,Sub中并没有定义属性c于d,而是在Sub的原型中定义。从这里可以知道,当function中没有定义先关属性的时候,会从其prototype中寻找,直到找到object.prototype为止。从而形成了一条链条。即为prototype chain。

下面对属性修改的时候原型链是怎么工作的。

  1. function Sub(){
  2.   this.a = "haha";
  3.   this.b = 5;
  4. }
  5. Sub.prototype.a = function(){
  6.   console.log("prototype method");
  7. };
  8. Sub.prototype.b = 6;
  9. Sub.prototype.c = 6;
  10. var testSub = new Sub();
  11. testSub.a = "hello";
  12. testSub.b = 100;
  13. testSub.c = 100;
  14. console.log(testSub.a);
  15. console.log(testSub.b);
  16. console.log(testSub.c);
  17. console.log(Sub.prototype.c);

结果输出:    

在代码的第13行中,设置属性c,从结果来看,并没有把Sub中prototype的属性c设置成100.而是在Sub中添加了一个属性c。这是javascript的特性,可以动态的给对象添加属性。在设置属性的值时,如果没有这个属性,不会从原型链中向上追溯,而是直接在对象中添加相应的属性。有点多态的意思。

当然我所写的这些笔记只是比较浅显的知识,方便回忆。更细致的东西在我分享的那几篇文档中,有兴趣的同学可以下载下来学习交流!

posted on 2013-09-20 22:56  wenlonghor  阅读(696)  评论(0编辑  收藏  举报

导航