本文呆鹅原创,原文地址: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),拉你进技术群,长期交流学习
  • 关注公众号「呆鹅实验室」,和呆鹅一起学前端,提高技术认知

点个赞支持我吧

上帝视角一文理解JavaScript原型和原型链的更多相关文章

  1. 理解javascript的闭包,原型,和匿名函数及IIFE

    理解javascript的闭包,原型,和匿名函数(自己总结) 一 .>关于闭包 理解闭包 需要的知识1.变量的作用域 例1: var n =99; //建立函数外的全局变量 function r ...

  2. 深入理解JavaScript作用域和作用域链

    前言 JavaScript 中有一个被称为作用域(Scope)的特性.虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域和作用域链,希望大家有所收获! ...

  3. JavaScript 开发进阶:理解 JavaScript 作用域和作用域链

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...

  4. JavaScript 开发进阶:理解 JavaScript 作用域和作用域链(转载 学习中。。。)

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...

  5. 理解JavaScript中的原型继承(2)

    两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客: 理解JavaScript中原型继承 JavaScript中的原型继承 这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误 ...

  6. 《深入理解JavaScript闭包和原型》笔记

    By XFE-堪玉 以下知识来源于对王福朋所写<深入理解javascript原型和闭包>的理解和整理 一切都是对象[引用类型],对象都是通过函数创建的[Funcion类型] 对象是属性的集 ...

  7. 理解javascript中的原型模式

    一.为什么要用原型模式. 早期采用工厂模式或构造函数模式的缺点:  1.工厂模式:函数creatPerson根据接受的参数来构建一个包含所有必要信息的person对象,这个函数可以被无数次的调用,工厂 ...

  8. 理解javascript 对象,原型对象、闭包

    javascript作为一个面向对象的语言,理解 对象.原型.闭包.模块模式等技术点对于成为一名合格的javascript程序员相当重要,多年没写过blog,今天就先拋个玉,在下基本也不做前端,但颇感 ...

  9. 如何理解JavaScript中的原型和原型链

    首先是一张关系图,避免抽象化理解时产生的困难 Function对象 函数对象是JavaScript学习中不可避免的一部分,而且这一部分相对重要且抽象 函数的创建方式有2种: 字面量创建 var foo ...

随机推荐

  1. centos7安装jdk11

    我下载的网址是http://jdk.java.net/11/ 找安装包的事就说到这里了.我是因为公司用的jdk8,但是,我给个人研究东西的时候,目前定的版本是jdk11 .另外,现在基本全线转到了op ...

  2. ArrayList源码剖析与代码实测

    ArrayList源码剖析与代码实测(基于OpenJdk14) 目录 ArrayList源码剖析与代码实测(基于OpenJdk14) 继承关系 从构造函数开始 从add方法深入 / 数组的扩容 其他的 ...

  3. PHP复杂变量

    eval($str="${${phpinfo()}}";)     →   可以执行phpinfo() ${phpinfo()} = {${phpindo()}} PHP复杂变量 ...

  4. 封装React AntD的dialog弹窗组件

    前一段时间分享了基于vue和element所封装的弹窗组件(封装Vue Element的dialog弹窗组件),今天就来分享一个基于react和antD所封装的弹窗组件,反正所使用的技术还是那个技术, ...

  5. Maven是什么? Maven的概念+作用+仓库的介绍+常用命令

    Maven系列1 1.什么是Maven? Maven是一个项目管理工具,它包含了一个对象模型.一组标准集合,一个依赖管理系统.和用来运行定义在生命周期阶段中插件目标和逻辑. 核心功能 Maven的核心 ...

  6. 设计模式也可以这么简单(7年开发老鸟PS注释总结)

    设计模式是对大家实际工作中写的各种代码进行高层次抽象的总结,其中最出名的当属 Gang of Four (GoF) 的分类了,他们将设计模式分类为 23 种经典的模式,根据用途我们又可以分为三大类,分 ...

  7. xml的复习

    xml的复习 1.概念:可扩展标记语言 2.功能: *存储数据    1.配置文件     2.在网络中传播 3.xml与html区别: xml语法严格,HTML语法松散 xml存储数据,HTML展示 ...

  8. 云计算openstack核心组件——glance— 镜像服务(6)

    一.glance介绍:              Glance是Openstack项目中负责镜像管理的模块,其功能包括虚拟机镜像的查找.注册和检索等. Glance提供Restful API可以查询虚 ...

  9. 程序员必须了解的知识点——你搞懂mysql索引机制了吗?

    一.索引是什么 MySQL官方对索引的定义为:索引(Index)是帮助MySQL 高效 获取数据的数据结构,而MYSQL使用的数据结构是:B+树 在这里推荐大家看一本书,<深入理解计算机系统的书 ...

  10. 解决npm被墙的问题

    npm存储包文件的服务器在国外,有时候会被墙,速度很慢,所以我们需要解决这个问题. http://npm.taobao.org/  淘宝的开发团队把npm在国内做了一个备份. 安装淘宝的cnpm np ...