彻底深刻理解 js 原型链之 prototype,proto 以及 constructor(二)

  • 2020-11-20
  • 本文字数:2226 字

    阅读完需:约 7 分钟

前言

如果你能够啃下教程一并且吃透原型链的几个概念的话说明你在前端飞仙的路上又进了一小步···学习最怕的不是慢而是站!这篇教程主要目的对原型链概念进一步加深理解

巩固下教程一的知识

来看下面的例子:

var text=new String("我是文字");function Persion(name,job){    this.name=name;    this.job=job;}Persion.myName="lxm";Persion.prototype.sayName=function(){    alert(this.name);}var perison1=new Persion("lxm","20")
复制代码

思考:判断下列表达式返回的值:

(两分钟之内对八道的算及格,剩下的同学回头接着理解教程一,传送门在此 [http://0313.name/2017/01/13/prototype-proto-constructor.html])

perison1.__proto__===Persion.prototype;perison1.name===Persion.name;perison1.prototype.__proto__===Object.prototype;Persion.prototype.__proto__===Object.prototype;Persion.__proto__===Function.prototype;Persion.constructor===perison1;Function.__proto__===Object.prototype;Function.prototype.__proto__===Object.prototype;typeof Persion.prototype;typeof Function.prototype;
复制代码

原型链图

这个图绝对是网络上独一无二独一份,此乃小米飞升教程独家秘籍!因为博主在学习过程中发现对文字的理解和记忆远远不如一个图来的更深更直观,更加透彻,为了您更好的学习原型链,博主特意花了一上午的时间用 mermaid 绘制了这个原型链的关系图,而且通过这个图我们能够发现很多有意思的事情 为了关系图更加直观和清晰,隐去了一些引用线路,其中:

  • 圆形代表对象的名字

  • 方形代表属性名

  • 实线代表对象的分界

  • 虚线代表引用

  • 菱形代表基本值

  • 原型链是单链,只往一个方向流向,没有回路

  • 只有 Function 的 proto 指向自己的 prototype,这也向我们解释了为什么 Function.prototype 类型是 function

  • 我们通过 proto 只能获取到原型对象中的方法和属性,所以 persion1 通过原型链是获取不到 Persion 的 myName 属性,但是我们可以通过原型对象的 constructor 来获取或者修改 Persion 的属性(这点太给力了)

请注意,有时候这个方法也不好使,因为原型对象的 constructor 是可以改变的,不一定指向原型对象所在的函数对象

继续上面的例子:

persion1.__proto__.constructor.myName="我变了耶!";console.log(Persion.myName); //我变了耶
复制代码

  • 普通对象的 proto_ 一定指向创造它的函数对象的 prototype

  • 原型对象的 proto 一定指向 Object.prototype!

  • 通过图我们可以简单理解,拥有原型对象属性的对象是函数对象,否则为普通对象

  • 原型链是有开始和尽头的,开始于 null,结束于普通对象

  • 所有的函数对象都是 Function 以 new 的方式创造出来了,包括 Function 自己且每个函数对象的 proto 都指向了 Function.prototype

  • Object 是所有对象的父类,我们也可以称之为基类,不过不要纠结于叫什么,因为我们通过图可以看到每一个对象(不管是原型对象还是普通对象还是函数对象)的通过原型链都可以引向 Object.prototype

以上九条我称为原型链之九句真言(不要太在意名字,我自己随便起的 ~)

意外收获:this.name 和 this.job 难道不应该在 Persion 中也有一份吗?无数个日夜,愚笨的博主对 this 的用法都不甚了解,直到我画出了这种图,我彻底明白了 this 的含义,就是谁运行包含 this 的这个函数,this 就把挂在它身上的包袱(属性)甩给谁! 看到了吗,persion1 调用了 Persion,那么自然多了 2 个属性,但是注意,name 跟 job 并不是 Persion 的属性!!

思考:图中没有画出 Object. proto 的指向,请问他指向哪?(请只依据九句真言解答)

思考题解答

思考:判断下列表达式返回的值:

perison1.__proto__===Persion.prototype;
复制代码

首先判断 perison1 是通过 new 方式被 Persion 创造出来的,依据九句真言第 4 条得出 :true

perison1.name===Persion.name;
复制代码

通过关系图可以看到不相等,我已经在意外收获中解答了,答案为:false

perison1.prototype.__proto__===Object.prototype;
复制代码

只看图可以看到 perison1 没有 prototype,是普通对象所以答案为:js 报错~~

Persion.prototype.__proto__===Object.prototype;
复制代码

参考九句真言第 5 条:答案为:true

Persion.__proto__===Function.prototype;
复制代码

Persion 为函数对象,参考九句真言第 8 条,答案为:true

Persion.constructor===perison1;
复制代码

Persion 是由 Function 创造出来的所以 Persion.constructor 指向 Function,答案为:false

Function.__proto__===Object.prototype;
复制代码

Function 我们已经反复强调是由自身创造所以 Function. proto ===Function.prototype;,答案为:false

Function.prototype.__proto__===Object.prototype;
复制代码

根据九句真言第 5 条,答案为:true

typeof Persion.prototype;
复制代码

答案为:object

typeof Function.prototype;
复制代码

答案为:function,注意这个是比较特殊的原型对象

思考:图中没有画出 Object.proto 的指向,请问他指向哪?(请只依据九句真言解答)

下面来分步解答

  • Object 属于函数对象

  • 依据九句真言第八条得出函数对象的 proto 都指向了 Function.prototype

  • 所以 Object. proto ===Function.prototype

这一点是不太好理解的,是 Function 创造了 Object,然后 Object 创造了 Function 的原型对象 prototype 所以就有了

Object.__proto__===Function.prototypeFunction.prototype.__proto__===Object.prototype
复制代码

不要太纠结于此,只要理解就好

结束语

好了,原型链的概念原理通过这 2 篇教程我相信大家已经滚瓜烂熟了!下面的教程,我们会着重研究下原型链在实际的应用!

本文转载自宜信技术学院。

原文链接

彻底深刻理解js原型链之prototype,proto以及constructor(二)