2013-11-12 09:56 1390人阅读 评论(3) 收藏 举报
 分类:
前端之Javascript(59) 

版权声明:本文为博主原创文章,未经博主允许不得转载。

  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. </head>
  6. <body>
  7. <script type="text/javascript">
  8. /**
  9. @authors Benjamin
  10. @date    2013-11-12 10:23:40
  11. 深入理解javascript 原型和原型链
  12. 最近不是很忙,空余时间整理最近几天看到的关于原型和原型链的文章,收获还是不小的。
  13. 今天十八届三中全会即将闭幕,期待新一届领导班子的改革方略,能够惠民吧
  14. 房价,户籍都是让80后很蛋疼的问题哈,当然,做为屌丝的我,肯定也是。
  15. 开篇先了解下两个很有用的属性:
  16. 一、__proto__属性:
  17. __proto__属性未来会成为ES6标准的一部分,目前,该属性在各个浏览器下的实现差别也许比较大.Firefox是最先实现的这个魔法属性(magic property)的浏览器,而且该属性在Firefox中的表现也最有望能成为标准.我们通常用的__proto__属性都是从Object.prototype上继承下来的,那到底__proto__与prototype什么关系呢?
  18. 1)所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function)
  19. 看看实例:
  20. */
  21. console.log(Number.__proto__   === Function.prototype) // true
  22. console.log(Boolean.__proto__  === Function.prototype) // true
  23. console.log(String.__proto__   === Function.prototype) // true
  24. console.log(Object.__proto__   === Function.prototype) // true
  25. console.log(Function.__proto__ === Function.prototype) // true
  26. console.log(Array.__proto__    === Function.prototype) // true
  27. console.log(RegExp.__proto__   === Function.prototype) // true
  28. console.log(Error.__proto__    === Function.prototype) // true
  29. console.log(Date.__proto__     === Function.prototype) // true
  30. /*
  31. JavaScript中有内置(build-in)构造器/对象共计12个(ES5中新加了JSON),这里列举了可访问的8个构造器。剩下如Global不能直接访问,Arguments仅在函数调用时由JS引擎创建,Math,JSON是以对象形式存在的,无需new。它们的__proto__是Object.prototype。如下
  32. */
  33. console.log("对象测试...");
  34. console.log(Math.__proto__ === Object.prototype);//true
  35. console.log(JSON.__proto__ === Object.prototype);//true
  36. /**
  37. * 上面说的“所有构造器/函数”当然包括自定义的。看下面的例子:
  38. */
  39. var Employee = function (){
  40. };
  41. function Person(){
  42. }
  43. console.log("自定义函数测试...");
  44. console.log(Employee.__proto__  === Function.prototype);//true
  45. console.log(Person.__proto__ === Function.prototype);//true
  46. /**
  47. * 由以上测试得出,所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身。所有构造器都继承了Function.prototype的属性及方法。如length、call、apply、bind(ES5)。另,Function.prototype也是唯一一个typeof XXX.prototype为 “function”的prototype。其它的构造器的prototype都是一个对象,下面来测试下:
  48. */
  49. console.log("类型测试中...");
  50. console.log(typeof Function.prototype) // function
  51. console.log(typeof Object.prototype)   // object
  52. console.log(typeof Number.prototype)   // object
  53. console.log(typeof Boolean.prototype)  // object
  54. console.log(typeof String.prototype)   // object
  55. console.log(typeof Array.prototype)    // object
  56. console.log(typeof RegExp.prototype)   // object
  57. console.log(typeof Error.prototype)    // object
  58. console.log(typeof Date.prototype)     // object
  59. console.log(typeof Object.prototype)   // object
  60. /**
  61. * Function.prototype 是一个空函数,我们来测试下
  62. */
  63. console.log("空函数测试...");
  64. console.log(Function.prototype);//function(){}
  65. //用alert来看会更直接点
  66. //alert(Function.prototype);//function(){}
  67. /**
  68. * 下面我们来看看Function.prototype 的__proto__是谁呢?看下面的测试
  69. */
  70. console.log("Function.prototype的__proto__测试...");
  71. console.log(Function.prototype.__proto__ === Object.prototype);//true
  72. /**
  73. * 那Object.prototype的__proto__又是谁呢?看下面测试
  74. */
  75. console.log(Object.prototype.__proto__);//输出null
  76. /*
  77. 2)所有对象的__proto__都指向其构造器的prototype
  78. 来看看以下实例
  79. */
  80. console.log("对象的__proto__测试中...");
  81. //函数声明
  82. function Foo(){
  83. }
  84. var foo = new Foo();//对象实例化
  85. console.log(foo.__proto__ === Foo.prototype);//true
  86. //函数表达式
  87. var Foo = function (){}
  88. var foo = new Foo();//对象实例化
  89. console.log(foo.__proto__ === Foo.prototype);//true
  90. /**
  91. * 看完自定义函数,下面我们来看看javascript引擎内置构造器
  92. */
  93. var
  94. arr = ["aaa", "bbb"],
  95. reg = /^abc$/g,
  96. obj = {
  97. name: "张三",
  98. age: 20
  99. },
  100. date = new Date(),
  101. error = new Error("fdasfdasfd");
  102. console.log("内置构造器的对象测试...");
  103. console.log(arr.__proto__ === Array.prototype);//true
  104. console.log(obj.__proto__ === Object.prototype);//true
  105. console.log(reg.__proto__ === RegExp.prototype);//true
  106. console.log(date.__proto__ === Date.prototype);//true
  107. console.log(error.__proto__ === Error.prototype);//true
  108. /**
  109. * 二、constuctor属性
  110. * constructor属性始终指向创建当前对象的构造函数,看下面的实例
  111. */
  112. var
  113. arr = ["aaa", "bbb"],
  114. reg = /^abc$/g,
  115. obj = {
  116. name: "张三",
  117. age: 20
  118. },
  119. date = new Date(),
  120. error = new Error("fdasfdasfd");
  121. console.log("constructor指向测试...");
  122. console.log(arr.constructor === Array);//true
  123. console.log(obj.constructor === Object);//true
  124. console.log(reg.constructor === RegExp);//true
  125. console.log(date.constructor === Date);//true
  126. console.log(error.constructor === Error);//true
  127. /**
  128. * 我们都知道函数是对象,对象都有prototype属性,那么这个prototype的constructor属性指向谁呢?
  129. * 由以下实例得出结论,其constructor指也向其构造函数
  130. */
  131. console.log("prototype的constructor属性指向测试...");
  132. //函数声明
  133. function Foo(){
  134. }
  135. console.log(Foo.prototype.constructor === Foo);//true
  136. //函数表达式
  137. var Foo = function (){
  138. };
  139. console.log(Foo.prototype.constructor === Foo);
  140. /**
  141. * 那么一个函数的实例指向谁呢?
  142. */
  143. function Foo(){
  144. }
  145. var f1 = new Foo();
  146. console.log("测试constructor实例化指向...");
  147. console.log(f1.constructor === Foo);
  148. console.log(f1.constructor.prototype.constructor === Foo);
  149. /**
  150. * 到此我们来必须来总结下子了:
  151. * f1 = new Foo();
  152. * f1.__proto__ === Foo.prototype.__proto__ === Object.prototype
  153. * Foo.prototype.constructor === Foo
  154. * Foo.__proto__ === Function.prototype.__proto__ === Object.prototype
  155. * 这样看起来貌似还是比较乱,下面用一张图来总结以上问题,如下图:
  156. */

  1. /**
  2. * 开一个怪例子,当我们重定义prototype对象时,constructor的行为会有什么变化呢?
  3. */
  4. function Foo(name){
  5. this.name = name;
  6. }
  7. Foo.prototype = {
  8. getName :function (){
  9. return this.name;
  10. }
  11. };
  12. var f1 = new Foo();
  13. console.log("重定义prototype对象测试...");
  14. console.log(f1.constructor === Foo); //false
  15. console.log(Foo.prototype.constructor === Foo);//false
  16. console.log(f1.constructor === Object);//true
  17. console.log(Foo.prototype.constructor === Object);//true
  18. /**
  19. * 是什么原因导致的此问题呢?来分析哈子,其实定义Foo.prototype = {}
  20. * 其实等价于Foo.prototype = new Object({"getName":function(){return this.name;}})
  21. * 因此Foo.prototype.constuctor === Obeject 返回true
  22. * 那么怎么让前面的两个false 变为true,做如下操作:
  23. */
  24. Foo.prototype.constructor = Foo;
  25. var f1 = new Foo();
  26. console.log("重新指向测试...");
  27. console.log(f1.constructor === Foo); //true
  28. console.log(Foo.prototype.constructor === Foo);//true
  29. </script>
  30. </body>
  31. </html>
___________________________________________________________________________________________________
 
 

在javascript的使用过程中,constructor 和prototype这两个概念是相当重要的,深入的理解这两个概念对理解js的一些核心概念非常的重要。

我们在定义函数的时候,函数定义的时候函数本身就会默认有一个prototype的属性,而我们如果用new 运算符来生成一个对象的时候就没有prototype属性。我们来看一个例子,来说明这个

function a(c){
this.b = c;
this.d =function(){
alert(this.b);
}
}
var obj = new a('test');
alert(typeof obj.prototype);//undefine
alert(typeof a.prototype);//object

从上面的例子可以看出函数的prototype 属性又指向了一个对象,这个对象就是prototype对象,请看下图

a.prototype 包含了2个属性,一个是constructor ,另外一个是__proto__

这个constructor  就是我们的构造函数a,这个也很容易理解。

那么__proto__ 是什么呢?

这个就涉及到了原型链的概念:

  每个对象都会在其内部初始化一个属性,就是__proto__,当我们访问一个对象的属性 时,如果这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__,于是就这样 一直找下去。

请看mozzlia 对它对它的描述

When an object is created, its __proto__ property is set to constructing function's prototype property. For example var fred = new Employee(); will cause fred.__proto__ = Employee.prototype;.

This is used at runtime to look up properties which are not declared in the object directly. E.g. when fred.doSomething() is executed and fred does not contain adoSomethingfred.__proto__ is checked, which points to Employee.prototype, which contains a doSomething, i.e. fred.__proto__.doSomething() is invoked.

Note that __proto__ is a property of the instances, whereas prototype is a property of their constructor functions.

不管你信不信,我们来看图

在后面如果加上 alert(obj.__proto__ === a.prototype) //true

同理,在这里我们来分析出new 运算符做了那些事情

  1. var obj={}; 也就是说,初始化一个对象obj。
  2. obj.__proto__=a.prototype;
  3. a.call(obj);也就是说构造obj,也可以称之为初始化obj。

我们将这个例子改造一些,变得复杂一点。

function a(c){
this.b = c;
this.d =function(){
alert(this.b);
}
}
a.prototype.test = function(){
alert(this.b);
}
var obj = function (){}
obj.prototype = new a('test');
obj.prototype.test1 =function(){
alert(22222);
}
var t = new obj('test');
t.test();//alert('test');

我们来分析下这个过程

由 var t = new obj('test'); 我们可以得到 t.__proto__ = obj.prototype,但是上面指定obj.prototype =new a('test'); 可以这样来看下

obj.prototype = p, p = new a('test'); p.__proto__ = a.prototype;

那么obj.prototype.__proto__ = a.prototype,由 t.__proto__ = obj.prototype 可以得出 t.__proto__.__proto__ = a.prototype,

所以对象t先去找本身是的prototype 是否有test函数,发现没有,结果再往上级找,即 t.__proto__   ,亦即obj.prototype 寻找test函数 ,但是obj.prototype 也没有这个函数,然后再往上找。即

t.__proto__.__proto__ 找,由于t.__proto__.__proto__ = a.prototype  在 a.prototype  中找到了这个方法,输出了alert('test')

从这里可以分析得出一个结论,js中原形链的本质在于 __proto__ 

再看看一个列子

function a(c){
this.b = c;
this.d =function(){
alert(this.b);
}
}
var obj = new a('test');
alert(obj.constructor);//function a(){}
alert(a.prototype.constructor);//function a(){}

根据上面讲到的__proto__ 我们来分析下,首先obj是没有constructor 这个属性的,但是 obj.__proto__ = a.prototype;就从

a.prototype中寻找,而 a.prototype.constructor 是就a,所有两者的结果是一一样的.

 

深入理解__proto__ 、constructor和prototype的关系的更多相关文章

  1. 彻底理解JavaScript中的prototype、__proto__

    虽然在JavaScript里一切皆对象,但为了理解原型链系统,我们需要将JavaScript的对象分为对象和函数两大类.在此基础上,JavaScript的原型链逻辑遵从以下通用规则: 对象有__pro ...

  2. javascript 中isPrototypeOf 、hasOwnProperty、constructor、prototype等用法

    hasOwnProperty:是用来判断一个对象是否有你给出名称的属性或对象,此方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员. isPrototypeOf是用来判断要检查 ...

  3. constructor、prototype、isPrototypeOf、instanceof、in 、hasOwnProperty

    constructor.prototype.isPrototypeOf.instanceof.in .hasOwnProperty等等 constructor:对象构造器.存在于原型对象中?,相当于p ...

  4. 面向对象的程序设计(二)理解各种方法和属性typeof、instanceof、constructor、prototype、__proto__、isPrototypeOf、hasOwnProperty

    //理解各种方法和属性typeof.instanceof.constructor.prototype.__proto__.isPrototypeOf.hasOwnProperty. //1.typeo ...

  5. js中__proto__和prototype constructor 的区别和关系

    https://www.zhihu.com/question/34183746 javaScript原型.原型链的定义? prototype:每个函数都有一个prototype(显式原型),这个属性是 ...

  6. <JavaScript>constructor、prototype、__proto__和原型链

    在看了网上很多相关的文章,很多都是懵逼看完,并不是说各位前辈们写得不好,而是说实在不容易在一两次阅读中理解透.我在阅读了一些文章后,自己整理总结和绘制了一些相关的图,个人认为会更容易接受和理解,所以分 ...

  7. JavaScript中__proto__与prototype的关系

    一.所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function) 1 2 3 4 5 6 7 8 9 Number.__proto__ ...

  8. 深入理解原型链(Prototype chain) __proto__

    原型链(Prototype chain) 原型对象也是普通的对象,并且也有可能有自己的原型,如果一个原型对象的原型不为null的话,我们就称之为原型链(prototype chain). A prot ...

  9. JavaScript中__proto__与prototype的关系(转)

    一.所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function) 1 2 3 4 5 6 7 8 9 Number.__proto__ ...

随机推荐

  1. Pandas的高级操作

    pandas数据处理 1. 删除重复元素 使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True keep参数: ...

  2. 进程池和multiprocess.Pool模块

    一.为什么要有进程池 首先,创建进程需要消耗时间,销毁进程也需要时间.其次,即使开启了成千上万的进程,操作系统也不能让它们同时执行,这样反而会影响程序的效率.因此我们不能无限制的根据任务开启或者结束进 ...

  3. JVM(12)之 可视化分析工具

    开发十年,就只剩下这套架构体系了! >>>   经过前几篇博文对堆内存以及垃圾收集机制的学习,相信小伙伴们已经建立了一套比较完整的理论体系!本篇博客就根据已有的理论知识,通过可视化工 ...

  4. spring(三):spring中BeanPostProcessor的使用

    spring中实现BeanPostProcessor的后置处理器 ApplicationContextAwareProcessor 进入该实现类内部 可以看到:该类帮我们组建IOC容器,判断我们的be ...

  5. Spring Boot 2 Webflux的全局异常处理

    https://www.jianshu.com/p/6f631f3e00b9 本文首先将会回顾Spring 5之前的SpringMVC异常处理机制,然后主要讲解Spring Boot 2 Webflu ...

  6. 【LeetCode】双指针 two_pointers(共47题)

    [3]Longest Substring Without Repeating Characters [11]Container With Most Water [15]3Sum (2019年2月26日 ...

  7. ltp-ddt eth_iperf_tcp iperf dualtest遇到的问题

    ltp-ddt eth_iperf_tcp server端:iperf -s -i 5 -w 1M client端将ddt的核心代码抠出来: iperf -c 1921.68.40.41 -m -M ...

  8. Go copy 的使用

    copy 可以将后面的 第2个切片的元素赋值copy 到第一个切片中 package main; import "fmt" func test () { s1 := []int{1 ...

  9. 第01章 Spring概述

    第01章 Spring概述 1.Spring概述 ①Spring是一个开源框架 ②Spring为简化企业级开发而生,使用Spring,JavaBean就可以实现很多以前要靠EJB才能实现的功能.同样的 ...

  10. java资料搜索网站

    http://yun.java1234.com/ 盘多多 B站 一个集成了很多springboot功能的地址 https://gitbub.com/runzhenghengbin/SpringBoot ...