假设我大学本科毕业论文的课题是[依据react现有的思想DIY一个react],我会怎么实现呢?做为一个react老用户的我,我经常有这样的疑问。那好,如今,我就在这根据现有的react概念和思想,按部就班地DIY一个简单版的react。一来,为本身立下一个react研究进程的里程碑;二来,跟你们交流交流。javascript
以下,我将这个按部就班的DIY过程细分为四个步骤:html
这四个步骤一路下来,确定会遇到不少新的概念。不要紧,概念是人定义的,只要是人定义的,就能够解释。何况,react的官方也解释过的。不过,只不过我会根据个人理解来解释。java
我的以为,第一个提出“virtual DOM”概念的人想必对DOM是有十分深刻的了解的。聪明的人一看就知道,virtual DOM这个概念确定是相对(real)DOM这个概念而言的。因此,想要理解virtual DOM,咱们不妨从理解(real)DOM开始。什么是DOM?node
javascrit犀牛书里面是这样说的:python
文档对象模型(DOM)是表示和操做HTML和XML文档内容的基础API。react
《Javascript DOM编程艺术(第二版)》里面将对定义的解释展开成三部分里来讲。也便是说:web
若是没有document(文档),DOM也就无从谈起。当建立了一个网页并将它加载到web浏览器中时,DOM就在幕后悄然而生。它把你编写的网页文档转换为一个文档对象。编程
在程序设计语言中,“对象”这个词的含义是很是明确的。“对象”是一种自给自足的数据集合。与某个特定的对象相关联的变量被称为这个对象的属性;只能经过某个特定对象去跳用的函数被称之为这个对象的方法。swift
DOM把一份文档表示为一颗树......更具体说,DOM把文档表示为一颗家谱树。家谱树自己又是一种模型。与使用“家谱树”这个术语相比,把文档称为“节点树”更准确。数组
MDN web docs里面是这样说的:
The Document Object Model (DOM) is a programming interface for HTML and XML documents. It represents the page so that programs can change the document structure, style, and content. The DOM represents the document as nodes and objects. That way, programming languages can connect to the page.
根据上面的定义,结合我本身的理解,咱们能够给DOM下这样的一个定义:
DOM是把文档(通常包括HTML文档和XML文档)转换为树型可编程文档对象的一种接口。
在这里,咱们也能够把这种接口理解为规范。由于当这种接口被众多浏览器所实现的时候,它无疑表明着一种行业规范。咱们也能够把这种接口理解为一种从真实文档到可编程对象的一种映射关系。而最终完成这种映射的操做是由浏览器内核来完成的。而现代浏览器支持的脚本语言javascript。因此,若是你以为上面咱们的定义实在太抽象的话,那么咱们能够简单地理解为:
DOM是一种关于如何在
HTML标签
跟javascript对象
之间创建一一对应关系的规范。
为何说是简单理解呢?由于标签不必定是HTML标签
,还能够是XML标签
。对象也不必定是javascript的,也能够是python的,以下:
# Python DOM example
import xml.dom.minidom as m
doc = m.parse(r"C:\Projects\Py\chap1.xml")
doc.nodeName # DOM property of document object
p_list = doc.getElementsByTagName("para")
复制代码
上面所说的javascript对象
在语义上说就是《Javascript DOM编程艺术(第二版)》中所提到的对象,也就是说传统面向对象编程语言所说的“对象”-有本身特定的属性和方法。这跟广义上“javascript对象”的概念仍是有区别的。更准确点,咱们称之为“原生DOM对象”。
假如,咱们有如下HTML文档:
<html>
<head>
<title>DOM Tests</title>
</head>
<body>
<div id="test"></div>
</body>
</html>
复制代码
那么HTML标签<div id="test"></div>
所对应的原生DOM对象就能够经过document.getElementById方法来得到。该原生DOM对象有本身的属性和方法:
let divElement = document.getElementById('test')
let textNode = document.createTextNode('我是文本节点')
// 是个javascript对象
console.log(typeof divElement) // "object"
// 有本身的属性,好比id
console.log(divElement.id) // "test"
/* 有本身的方法,好比appendChild()
* 最终在文档中的表现为:<div id="test">我是文本节点</div>
*/
divElement.appendChild(textNode)
复制代码
好,弄清楚什么是“(real)DOM”以后,那么“virtual DOM”就比较好理解了。顾名思义,virtual DOM无非指的就是非真正的DOM,是虚拟的。虚拟,虚拟,那拟的是谁的呢?固然是“(real)DOM”啦。在DOM的世界里面,它们是用一个原生DOM对象来描述文档树的一个节点的。那么与此类比,virtual DOM的世界咱们用一个pure javascript object
(也就是咱们平时所说的字面量对象,有点想swift的hash table)来描述一个文档节点,好像也说得通。咱们说干就干。
// 字面量对象
let virtualDOM ={}
复制代码
原生DOM对象有nodeName属性,表明着文档元素的标签名称,咱们也得有。为了区别于原生,咱们取名为“type”。
// 字面量对象
let virtualDOM ={
type:string
}
复制代码
文档元素通常都会有众多属性,对应到原生DOM对象中,它也有一个叫attributes的属性。仍是为了区别与原生,咱们取名为“properties”,简写为“props”。不过相比DOM里面的“元素属性集合也是一个节点集合(nodeList)”,咱们这里简化一下,也就是说仍是用key-value组成的字面量对象来表示属性集合。
// 字面量对象
let virtualDOM ={
type:string,
props:{
prop1:value1,
prop2:value2,
......
}
}
复制代码
由于文档具备自然的树状结构,因此一个元素与另外的一个元素一定存在这样那样的关系。要么A是B的父节点,要么C是B的兄弟节点。在DOM中,咱们正是经过这种关系来遍历整个文档树。仍是拿上面的divElement元素举例。
其实,在文档树中,一个元素跟另一个元素的关系无非就两种:父子关系和兄弟关系:
divElement.parentNode -> <body />
divElement.previousSibling -> null // divElement并无往下的兄弟节点
divElement.nextSibling -> null // divElement并无往下的兄弟节点
divElement.childNodes -> ['我是文本节点']
复制代码
那么对比原生DOM对象,在virtual DOM对象上,咱们该如何设计出对应的数据结构来体现这两种关系呢?答案是多样化的。你能够这样设计:
// 字面量对象
let virtualDOM ={
type:string,
props:{
prop1:value1,
prop2:value2,
......,
children:[child1,child2,......]
}
}
复制代码
上面的这种设计,就是让children也成为了一个属性,只不过使用的时候,不能把它看成一个真正的属性来用。
你也能够这样设计:
// 字面量对象
let virtualDOM ={
type:string,
props:{
prop1:value1,
prop2:value2,
......
},
children:[
child1,
child2,
......
]
}
复制代码
这种设计相比前者,把children属性放在与props属性平级的层级上,我的感受从结构角度上来评价,后者更好理解。可是不知道为啥,react官方采用了前者的设计方案。不管哪一种设计方案,都是在virtual DOM节点中保存一个指向它的全部子节点的引用来体现父子关系的。而数组中相邻的两项则是兄弟关系的体现。
至此,咱们经过理解DOM,并运用依样画葫芦的手法,咱们完成了virtual DOM对象的数据结构的设计。这是十分基础且重要的一步。若是说,现实世界是由原子堆叠而成的话,那么咱们也能够说,文档就是由节点(node,node又分为elecment node,text node和 attribute node)堆叠而成,DOM就是由原生DOM对象堆叠而成,virtual DOM就是由virtual DOM对象堆叠而成的。在react的世界里面,virtual DOM对象是构建应用的基本单元。咱们正是经过把[对virtual DOM的更新]映射[为对real DOM的更新],再经过浏览器把[对real DOM的更新]映射为[对文档的更新]来完成界面的更新的。
下一篇文章,我就来谈谈如何使用javascript来实现这种“映射”。 更具体地说,就是如何将
{
type:'div',
props:{
id:'test',
children:['我是文本节点']
}
}
复制代码
最终“映射”为真正文档上的一个元素节点:
<div id="test">我是文本节点</div>
复制代码