关于前端:上帝视角一文理解JavaScript原型和原型链

5次阅读

共计 3701 个字符,预计需要花费 10 分钟才能阅读完成。

本文呆鹅原创,原文地址:https://juejin.im/user/307518987058686/posts

前言

本文将从 上帝角度 解说 JS 的世界,在这个过程中,大家就能齐全了解 JS 的原型和原型链是什么,之后还会基于原型和原型链常识拓展一些相干常识。

浏览本文前能够思考上面三个问题:

  • 你了解中的原型和原型链是什么?
  • 你能齐全了解并画出原型和原型链的关系图吗?
  • 基于原型和原型链拓展的相干常识你理解多少?

经典图

大家接触原型和原型链时应该都看到过上面这张图。刚开始理解的时候,看到这个图大都不太明确,甚至一脸懵,这里先留个坑。

先祭图,让暴风雨来得更剧烈些!

上面开始解说 JS 世界是如何一步步诞生的,看完你也就齐全明确这张神图啦。

无中生有

起初,上帝 JS 掌控的世界什么都没有。
上帝 JS 说:没有货色自身也是一种货色啊,于是就有了null

当初咱们要造点儿货色进去。然而没有原料怎么办?
有一个声音说:当初不是有 null 了嘛?
上帝说:那就无中生有吧!

JavaScript 中的 1 号对象产生了,无妨把它叫做机器 1 号。
这个机器 1 号可不得了,它是 JS 世界的第一个对象,它是真正的万物始祖。它领有的性质,是所有的对象都有的。
__proto__是什么呢?是“生”的意思,或者换成业余点的叫法“继承”。

有中生有

刚开始造物,上帝当然想继续下去啦,既然曾经有了一个始祖级的机器,剩下就好办了,因为毕生二,二生三,三生万物嘛。

不过上帝很懒,他不想一个一个地亲手制作对象。于是他做了一台可能制作新对象的货色:

他给这个货色起了一个名字:Object。

然而这个 Object 制作对象时候,须要有一个模版,当初只有机器 1 号,它就取了机器 1 号当模版。图中的 prototype 就代表模板对象。

如何启动制作呢?通过 new 命令。你按下“new”按钮,新的对象就造出来了。

把这个过程写成代码就是:

var obj = new Object();

轰轰烈烈的造物静止开始了……

有生万物

有一天,上帝 JS 去看了上帝 Java 造的世界,发现上帝 Java 的世界好精彩,可不仅仅有 Object 对象,还有 String 对象、Number 对象、Boolean 对象等等。

于是上帝就思考了:那我能够多让机器造一些对象啊。

然而上帝感觉把这些工作都交给机器 1 号的话,机器 1 号太累了,不如让机器 1 号造一个机器 2 号来做这些工作。

重点阐明下“这些工作”指的是:总体负责制作所有的对象,蕴含 Object、String、Number、Boolean、Array,甚至还有之后的 Function。当然它只是负责制作,并不一定会亲手去制作对象,能够通过制作对应的机器来帮忙它制作对象

于是就有了机器 2 号:

(注:__proto__写起来麻烦,咱们之后用 [p] 来代替)

可能有的小伙伴留神到啦,Object也指向了机器 2 号,这是因为机器 2 号是负责造对象的,当然也负责造 Object 对象啦。

接下来,既然机器 2 号是由机器 1 号造出来的,而 String、Number、Boolean、Array 这些对象是由机器 2 号造出来的,所以它们其实和 Object 一样,也自带了 new 命令:你按下“new”按钮,新的对象就造出来了。

然而 Object 有本人的模板:机器 1 号。而 String、Number、Boolean、Array 它们有模板吗?

其实机器 2 号在创立它们的时候并不是间接创立它们的,而是先创立了对应对象的机器作为模板,而后再由各自的机器来创立它们。

具体我画了 String 相干的图(其余 Number、Boolean、Array 等都是同一个情理的):

这样,这张图显示了 JS 世界中那些最根本的机器自身的原型链,以及它们的模板对象的原型链。

  • 机器 1 号制作了机器 2 号,机器 2 号总体负责各种对象的制作
  • 然而机器 2 号并不是间接造各种对象,而是通过先建造对应的机器,再由对应的机器来制作对象。如:对于 String,机器 2 号 先制作了 机器 String 号 ,而后由 机器 String 号 来制作 String,机器 2 号 只负责总体管制
  • 尽管机器 2 号制作了各种各样的机器,然而因为机器 2 号是由机器 1 号制作的,所以这些被制作的机器所属权还是归于机器 1 号的,毕竟机器 1 号是始祖级的。
  • 对象和对应的机器,通过 prototype 来连贯。如:对于 String,机器 2 号 String通过 prototype 连贯
  • 每个机器都有且只有一个的对象,每个对象也都有且只有一个机器作为模板。

万物缺生机

上帝看着越来越丰盛的世界非常高兴,然而总感觉毛病什么?

一个声音说:世界短少生机呀
上帝说:那就造一个 能让世界动起来的对象

上帝给这个新对象的起了个名字叫:Funciton
然而这个制作 Function 的工作交给谁好呢,让世界动起来当然是十分重要的,那就交给机器 2 号吧,由机器 2 号亲手负责 Function 的制作

于是,Function 对象就呈现了

让咱们来察看一下 Function 对象:

  • 它是由机器 2 号亲手制作的,所以它们之间有 prototype 相连
  • 而机器 2 号又是制作所有对象的负责者,所以它们之间有 __proto__ 相连

于是咱们失去了 Function 的一个十分特地的性质:

Function.__proto__ === Function.prototype

于是 JavaScript 的世界的变成了上面的样子:

到当初咱们能明确啦:

  • 机器 1 号 = Object.prototype
  • 机器 2 号 = Function.prototype
  • 机器 String 号 = String.prototype

世界动起来

自从有了 Function,世界就越来越有生机了,有什么事须要做,用 new Function()造个新 Function 来做就行了。

然而刚造出来的 Function 机器 很难用,用法就像上面这个:

let Foo = new Function("name", "console.log(name)");

Foo('dellyoung'); // 控制台打印出:dellyoung

你想要造一个 Function,无论是输出的内容(参数)还是要做的事件 (函数体) 都得弄成字符串,能力胜利造出来。

上帝用起来好受啊,他就改装了一下这个 Function,给他来了个语法糖

function Foo(name) {console.log(name);
}

Foo('dellyoung'); // 控制台打印出:dellyoung

(注:下面两段代码是齐全等价的。)

当初造一个新的 Function 就难受多啦!

以造 Foo() 为例,于是 JavaScript 的世界的变成了上面的样子:

Function 这个对象比拟非凡,它 new 进去后,就是一个全新的对象了,function Foo()(留神:它等价于 let Foo = new Function())和 ObjectStringNumber 等这些对象一样,都是对象。

既然都是对象,当然 function Foo() 也是由机器 2 号来管制制作的,然而机器 2 号很忙,它没有精力间接制作 function Foo(),机器 2 号是通过制作出一个 制作 function Foo()的机器 来制作function Foo()

咱们称 制作 function Foo()的机器 机器 Foo()号

当然既然是机器,所以 机器 Foo()号 也是 由机器 1 号 管制的,起因上文讲过:

尽管机器 2 号制作了各种各样的机器,然而因为机器 2 号是由机器 1 号制作的,所以这些被制作的机器所属权还是归于机器 1 号的,毕竟机器 1 号是始祖级的。

而且这个 function Foo() 对象制作进去后,它既然是对象,所以它和 Object、String、Number 等对象一样,能够通过 new Foo() 制作出新的对象,模板就是用的 机器 Foo()号

听起来如同有点绕,咱们看看图就明确啦

上图中:

  • 机器 1 号 = Object.prototype
  • 机器 2 号 = Function.prototype
  • 机器 String 号 = String.prototype
  • 机器 Foo()号 = Foo.prototype
  • [p] = __proto__

回到事实

当初咱们就能齐全了解并残缺的画出原型和原型链的关系图啦:

其实能够被用来 new 的对象或函数,咱们都能够称之为构造函数,每个构造函数都和它的机器 (也就是XXX.prototype) 通过 constructor 相连, 咱们来画出构造函数和它们的constructor

为了清晰一些,上图用 [con] 示意constructor

当初这张图就是残缺的原型和原型链的关系图啦

用正式的语言总结一下就是:

  • 子类的__proto__属性,示意构造函数的继承,总是指向父类。
  • 子类 prototype 属性的__proto__属性,示意办法的继承,总是指向父类的 prototype 属性。

当初咱们再看这张神图:

是不是很简略啦,不过就是把咱们画的图向右旋转了 90°。

而且认真看一遍,咱们的关系图蕴含的更加的全面。

填坑结束。下篇文章我会以此为延长,从底层解说 JavaScript 的 this,看完你会彻底了解 this 为何物,关注我

看完两件事

  • 欢送加我微信(iamyyymmm),拉你进技术群,长期交流学习
  • 关注公众号「呆鹅实验室」,和呆鹅一起学前端,进步技术认知

???? 点个赞反对我吧 ????

正文完
 0