一文读懂原型链 prototype和__proto__详解

目录

1.原型对象 prototype

2.prototype 和 __proto__

3.原型链 

4.补充 

5.原型链总结


1.原型对象 prototype

我们首先总结一下原型对象的作用:

  1. 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中去。
  2. 当我们访问对象的一个属性或者方法时,它会先在对象自身中寻找,如果找到要查找的属性或者方法就会直接使用,如果没有就会去原型对象中查找,找到了就会直接使用。
  3. 在我们创建构造函数时,可以将对象的共有属性或方法,统一添加到构造函数的原型对象中去。这样做的好处就是不用分别为每一个对象添加这些共有的属性或方法,也不会影响到全局作用域,同时每个对象也都具有这些属性和方法。可以说给原型对象添加属性或者方法,函数的所有实例对象都会自动拥有原型中的属性和方法。

这里我们首先创建一个构造函数对象:




  • 普遍来说,对于所有函数,每个函数是都会含有一个prototype属性,它默认指向一个object空对象(也称为原型对象)。
  • 原型对象中都有一个constructor属性,它是指向函数对象的。

2.prototype 和 __proto__

  1.  每个函数都有一个prototype属性,可以称之为显式原型属性。
  2. 每个对象的实例对象都有一个__proto__属性,可以称之为隐式原型属性。
  3. 实例对象的隐式原型的值和其构造函数的显式原型的值所对应。

 在实际执行过程中,其内存图如下所示:

一文读懂原型链 prototype和__proto__详解_第1张图片

 上述过程可以总结为:

  • 函数的prototype属性:在定义函数时自动添加,默认值是一个空的Object实例对象。
  • 实例对象的__proto__属性:在创建实例对象时自动添加,默认值为其构造函数的prototype属性值。
  • 这里需要注意在ES6之前,程序员能直接对显式原型进行操做,但不能直接操作隐式原型,因为会涉及到一些安全问题。

3.原型链 

由上述讲解可知,在访问一个实例化对象的属性或者方法时,会先在自身属性中查找,找到则返回;如果找不到会沿着自身__proto__所指向的位置查找。我们思考一个问题,所查找的属性或者方法在实例化对象沿着自身的__proto__属性中没有找到呢,它会直接返回没有找到这个结果还是说会继续沿着某条链查找。

这里我们提出Objecct原型对象中存在的方法:toString() ...

上述toString()方法每个函数的prototype属性都是拥有的,可是这与我们之前所说的”每个函数是都会含有一个prototype属性,它默认指向一个object空对象“不是冲突了吗。其实并不冲突,每个函数的prototype属性确实默认是指向一个空的Object实例化对象的,那么既然是指向空的Object实例化对象,我们第二小节提到的只要是实例化对象必然就会有__proto__属性,而且这个__proto__属性是与其构造函数 Obejct( ) 的prototype属性对应起来的。我们根据第2小节的JS代码就会有如下图所示的内存空间关系:

一文读懂原型链 prototype和__proto__详解_第2张图片

上图中Object函数对象的prototype原型对象中也是有__proto__属性的,且其值为null,所以这个原型对象就是原型链中的查找尽头。

这里我们需要解释一下当 F 的实例化 f 为什么沿着原型链查找T()时会报错 ”Uncaught TypeError: f.T is not a function“,f.T  却是undefined :因为原型链的尽头__proto__值为null,当实例化对象查找到原型链的尽头时,还没有找到要找到属性或者方法,就会得到原型链尽头__proto__的值null --->这里f.T()其实对应了null(),对于null()来说肯定报错f.T()不是一个函数;而f.T则由于原型链尽头__proto__的值为null,返回了undefined。

4.补充 

我们最后还需要补充几点:

  1. 假设有一个函数function Foo(){ },它理所应当有prototype属性,那么它有没有__proto__属性呢?答案是有的,可是我们之前不是说只有实例化对象才会有__proto__属性吗?没错,这个说法肯定是没有丝毫问题的,那么我们按照逻辑推下去function Foo(){ } 一定是一个实例化的对象,其实对于这个函数是这样的:function Foo() { } ---->  var Foo = new Function()        我们很明显的可以看出函数 Foo() 也是一个实例化的对象,所有它既有prototype属性也还有__proto__属性,且其隐式原型__proto__与function Function()的显式原型prototype所对应。
  2. 对于构造函数function Function()也是同样的产生方式: Function = new  Function() 所以Function()的隐式原型__proto__是与Function()的显式原型prototype所对应的。

  3. 最后就是function Object():  Object = new Function()      所以Object函数对象也同样有隐式原型__proto__,且其__proto__与 Function()的显式原型prototype所对应。

最终我们原型链的图如下所示: 

               

一文读懂原型链 prototype和__proto__详解_第3张图片

 5.原型链总结

        1.访问一个对象的属性/方法时: 

               · 先在自身属性/方法中查找,找到则返回。

               · 如果没有找到,就会沿着__proto__这条链去查找,找到也会返回。

               · 如果查到了原型链的尽头还是没有查找到,则返回undefined。

        2.因为在实例化对象查找属性或者方法时总是沿着__proto__隐式原型链查找,所以原型链又称作隐式原型链

        3.原型链的作用:查找对象的属性或者方法。

你可能感兴趣的:(原型模式,javascript,前端,prototype)