从 __proto__ prototype 说起

先来做个复习,ES5中有有几种数据类型呢?

  • 5种基本数据类型
    • Undefined
    • Null
    • Boolean
    • Number
    • String
  • 1种复杂数据类型
    • Object

除了基本数据类型,万物皆对象,记住这个很重要,这体现了js设计的哲学思想,和现实生活事物存在的关系一模一样。

接触js也一年有余了,刚开始看各种概念感觉在记忆,先能上手干活的感觉也让自己先用了js起来,回头来看很多概念你不真正用的有些感悟可能真的很迷糊,就像今天突然问自己__proto__ 是干嘛的,和它长得很像的prototype又是干嘛的,为啥不都用一个,看起来读起来都那么像。。。。ok,我尽量把自己所思所想记录下来,能表达的清晰,哈哈其实我理解能力有限哈哈哈。

不让自己思维绕弯子,当我们想完全弄清楚一件事情的时候,那么最好搞清楚我们最关心的两个问题:它是什么,有什么用,那么先直接给几个定论(如果有误区请各位大神指正):

是什么

  • __proto__
    每个对象都拥有的属性

  • prototype
    每个方法都拥有的属性

有什么用

  • 让js拥有了原型链来达到共享数据和方法的目的

好了,先来说是什么,那么让我们想想几个关键字:每个对象每个方法,那么记得开始很重要的一件事儿么,就是js中万物皆对象,那么方法是什么鬼,没错,方法也是对象,一种需要特殊拎出来的对象,特殊在哪呢,那么牛逼。。。。其实就是要理解是什么中,方法比对象更牛逼一些,因为它既是对象又是方法。。。。所以呢?说明方法既有__proto__属性又有prototype属性。那么我们可以开始看例子来加深理解:

var A = function(){}; // A是一个方法,当然也是个对象
var a = new A(); // a是一个由A创造出的对象,不是方法  

//看一看对象非方法的行为
console.log(a.__proto__); //object
console.log(a.prototype); //undefined, 对象没有 

//看一看方法的行为,方法也是对象哦

console.log(A.__proto__); //function
console.log(A.prototype); //object

是不是有点晕了,哈哈我也是,别急至少我们验证了我们是什么的定论,接下来研究下有什么用,其实在这之前难道不好奇a.__proto__,a.prototype, A.__proto__,A.prototype, 都等于谁吗?那我们来接着验证。

console.log(a.__proto__ === A.prototype); //true
console.log(a.prototype === undefined); //true

console.log(A.__proto__ === Function.prototype); //true
console.log(A.prototype === a.__proto__); //true

矣,是不是看出来点神马?没错,有一点点原型链的感觉了,那么继续

//先看a这条链
console.log(a.__proto__.__proto__ === A.prototype.__proto__); //true
console.log(a.__proto__.__proto__ === Object.prototype);//true
console.log(a.__proto__.__proto__.__proto__ === Object.prototype.__proto__);//true
console.log(a.__proto__.__proto__.__proto__ === null);//true


//再看看A这条条链
console.log(A.__proto__.__proto__ === Function.prototype.__proto__);//true
console.log(A.__proto__.__proto__ === Object.prototype);//true
console.log(A.__proto__.__proto__.__proto__ === Object.prototype.__proto__);//true
console.log(A.__proto__.__proto__.__proto__ === null);//true

矣,像不像两个链条了?而且这两个链条还有些关系呢,头大?我也是。。要不来张图吧

说明一下,这里有两类事物:对象和对象方法,对象方法是我起的名字。。。哈哈,记住方法也是对象,js万物皆对象哦。其中红色框是表示的原型对象,网上很多图把它和拥有它的对象画在一起,我觉得不够直观,所以就自己画出来啦,对照上面总结的是什么和原型链的验证,再配合这张图,个中体会,哈哈有木有豁然开朗的赶脚,如果没有不要紧,多看几遍喽哈哈哈

然后我们来看下,这张图几个有意思的地方。

  • 首先看a对象,有三种不同方式创建的a对象,它们的原型链指向是不同的哦,体会一下,是不是还是很合情合理。
  • Function的__proto__指向的是自己即Function的prototype,而Function的prototype的__proto__指向的是Object的prototype,而Object的__proto__指向了Function的prototype,what????没错,看图,它们形成了一个环状引用。。。所以知道为什么说方法也是对象了吧,看到没,万物归终,最后都指向了Object, 而Object的原型链又指向谁了呢,一个大大的null,哈没错,null是到头了,空也是终极对象啊,看到js的哲学了么,其实万物皆空,善哉善哉。。。
  • 最后来解决文章刚开始提出的问题,__proto__和prototype为啥会有两个,用一个不行嘛,看了图或许我们能参悟到了吧
    • __proto__才是原型链, 除了第三种方式创建的对象和Object的终极指向,它始终指向prototype
    • prototype是一个原型对象,其中包含的属性(用户自我添加的)就是我们总结的有什么用中提到的,就是包含共享的数据和方法的对象
    • 至于为什么有两个,很简单,两个人干的事儿不一样,不能互相代替,__proto__是指向共享原型对象的访问句柄,而prototype是被访问的共享原型对象,打个不恰当的比喻,大家同时用右手搭在别人肩上排成一排的时候,链接人与人之间的手和人能一样么,缺少一个,还能是链条么,当然不能拉,突然想起来,觉得是不是很像一种数据结构,虽然我不常用,但是感觉哇在这里见到了呢,是什么呢?没错,是链表!

这个js原型链系列的文章还会继续完善,希望自我总结,也希望读到的人能有所帮助,也更希望各位大神多多指点~

update for simona