彻底搞清楚 JavaScript 的原型和原型链(一)

简介: JavaScript真的挺无语的,怪不得看了那么多的介绍文章还是一头雾水,直到自己终于弄懂了一点点之后才深有体会:先从整体说起吧,发现没有基础做依据,那都是空中楼阁;先从基础开始介绍吧,又发现基础是个蛇头咬蛇尾的圆环,无从下手,应该先整体介绍。于是介绍本身就成了一个死循环。。。

主要内容:

  • 对象的继承树。
  • 函数的继承树。
  • 函数 VS 对象
  • prototype VS  _ _ proto__
  • 继承 VS 组合
  • 自己定义函数(class),以及实现继承

寻找原型链的“源头”

网上有一个梗:万物基于MIUI。虽然是一句调侃,但是也表达源头的重要性。

看过一些高手写的关系图,应该是非常专业,但也正是因为太专业了,所以才导致新手看的是一头雾水。那么对于先手来说,有没有简单一点的方式呢?我们可以借鉴一下面向对象的思路。

提到面向对象,大家都会想到基类(超类、父类)、子类、继承、多态等。为啥容易记住呢?因为继承关系非常简单,从基类开始,一层一层继承下去,结构非常清晰明了。

我觉得应该借鉴一下这种表达方式,也许这种方式并不契合JavaScript,但是我觉得应该比较方便初学者入门。

经常听说,JavaScript 的世界是基于 Object 的,这句话对但是又不对,为啥这么说呢?我们来看看 Object 的结构:(使用 console.dir() 可以看到细节  )

console.dir(Object)

65.png

Object的结构组成

首先请注意一下那个 f 的标识,这表示 Object 其实是一个函数(从 JavaScript 的语法角度来看),我们来验证一下:

66.png

Object 其实是函数

这到底是怎么回事呢?后面细说,先把找到源头才好理解。

这个 Object 并不是源头,因为还有 prototype 和 __ proto__, 我们先看看 Object.prototype 的结构:

Object.prototype

console.dir(Object.prototype)

67.png


Object原型的结构

可以看到,Object.prototype 才是源头,因为 Object.prototype 没有 prototype(当然没有),_ _ proto__ 也是 null,我们来验证一下:

console.dir(Object.prototype.prototype)
console.dir(Object.prototype.__proto__)

68.png

Object 验证prototype

69.png

Object 验证 proto

Object.__proto __

70.png


103-object2.png

这是啥?是不是很头晕,这个其实指向的是 Function的原型,我们来验证一下:

71.png

103-object2验证.png

这是咋回事?后面再解释。


小结

是不是有点晕,让我们来梳理一下思路:

72.png

Object的三个重要属性

如果看上面的图有点晕的话,可以先看下面的图,灰线说的是构造函数的关系,可以先跳过。(终于画出来了那种绕圈圈的图,向着专业又迈出了一步)

73.png

Object的两个重要属性

  • 思路一:Object有两个属性,一个是对象原型,一个是函数原型。
  • 思路二:Object有两个指针,一个指向对象原型,一个指向函数原型。

我觉得思路二更适合一些,这个是理解 JavaScript 的原型链的第一个门槛,如果绕不清楚的话……没关系,往下看就好,我也是把下面都写出来,然后回头才整理出来这个图的。。。(这个也是给继承和组合做个铺垫)

构建一颗大树 —— 对象的继承关系

找到源头之后,我们就可以构建一颗大树了。

构建原则:xxx.prototype._ _ proto__ === Object.prototype 即:Object.prototype 看做父类,然后把其“子类”画出来。


74.png

对象的树

这下是不是清晰多了呢?我们来验证一下:

  • Array

75.png

190-Array原型.png

  • String:


76.png


String原型

好长好长,差点截不下来。

  • Number

77.png

Number原型

  • BigInt

78.png

BigInt原型

  • Boolean

79.png


Boolean原型

  • Symbol


80.png

Symbol原型

  • Date

81.png

Date原型

  • RegExp  (正则表达式)

83.png

RegExp原型

  • Math

84.png


Math

共同点

每种类型都有自己的成员,然后_ _ proto__ 指向 Object.prototype。

特例

这里有几个特殊情况:

  • Math
    没有原型,或者说原型就是 Math 自己。

  • Array
    这个比较奇怪。

  • null 和 undefined
    这对兄弟先当做特殊情况来处理。

  • Function
    Function.prototype._ _ proto__ 也是指向 Object.prototype的,但是 Function.prototype 是一个 f

  • Object
    如果说 Object.prototype 是基类的话,那么Object是啥呢?其实 Object 是函数。是不是有点晕?从JavaScript 语法的角度来说,不仅 Object 是函数,String、Number这些都是函数。

再构建一颗大树 —— 函数的继承关系

观察上面的图(对象的树)可以发现,我写的都是xxx.prototype 的形式,那为啥不直接写xxx呢?

因为从 JavaScript 的语法的角度来看,Object、String、Number、Array、Function等都是函数,Object.prototype、String.prototype 等才是对象。我们从函数的角度来构造另一颗大树。

依据:xxx._ _ proto__ === Function.prototype 即:把Function.prototype看做父类,把他的子类(__ proto__指向他的)都画出来。


85.png

函数的树

这里加上“()”,明确一下,然后我们来看一下具体的结构:

  • Function

86.png

200-Function原型.png

  • String

87.png

String()

  • Number

88.png

Number()

  • Boolean

89.png

Boolean()

  • BigInt

90.png


BigInt()

  • Symbol

91.png

Symbol()

  • Date

92.png

Date()

  • RegExp

93.png

RegExp()

  • Array

94.png


相关文章
|
25天前
|
JavaScript 前端开发 开发者
理解JavaScript中的原型链:基础与实践
【10月更文挑战第8天】理解JavaScript中的原型链:基础与实践
|
3月前
|
JavaScript 前端开发
如何在JavaScript中实现基于原型的继承机制
【8月更文挑战第14天】如何在JavaScript中实现基于原型的继承机制
29 0
|
2天前
|
JavaScript 前端开发
如何使用原型链继承实现 JavaScript 继承?
【10月更文挑战第22天】使用原型链继承可以实现JavaScript中的继承关系,但需要注意其共享性、查找效率以及参数传递等问题,根据具体的应用场景合理地选择和使用继承方式,以满足代码的复用性和可维护性要求。
|
12天前
|
JavaScript 前端开发 开发者
探索JavaScript原型链:深入理解与实战应用
【10月更文挑战第21天】探索JavaScript原型链:深入理解与实战应用
21 1
|
20天前
|
JavaScript 前端开发 开发者
深入理解JavaScript原型链:从基础到进阶
【10月更文挑战第13天】深入理解JavaScript原型链:从基础到进阶
19 0
|
20天前
|
JavaScript 前端开发 开发者
原型链深入解析:JavaScript中的核心机制
【10月更文挑战第13天】原型链深入解析:JavaScript中的核心机制
24 0
|
20天前
|
JavaScript 前端开发 安全
深入理解JavaScript原型链:从基础到进阶
【10月更文挑战第13天】深入理解JavaScript原型链:从基础到进阶
26 0
|
2月前
|
JSON JavaScript 前端开发
js原型继承|26
js原型继承|26
|
2月前
|
JavaScript 前端开发
JavaScript prototype(原型对象)
JavaScript prototype(原型对象)
30 0
|
2月前
|
JavaScript 前端开发
JavaScript基础知识-原型(prototype)
关于JavaScript基础知识中原型(prototype)概念的介绍。
37 1