“ 在使用React时,我们能经常听见虚拟dom,那虚拟dom是什么?它的原理又是什么?我们该如何来实现一个简版的虚拟dom呢?”
其实虚拟dom不是什么何方神圣,它本质上就是js对象,该对象就是对dom的一种描述方式。换句话来说:js对象模拟dom结构,将dom的变化对比放到了js层来做。
如果你读过源码的话,肯定觉得要想实现虚拟dom对象是很简单的一件事情。首先我们需要知道JSX是什么?它其实只是语法糖而已,babel会将它编译为React.createElement
函数调用;那createElement函数返回的是什么呢?做一个测试代码如下所示:
1 | import React, {Component, createElement} from 'react'; |
得到的element值是一个对象,具体结果如下图所示:
element对象返回值图
在这里我就不具体讲述createElement方法的源码是什么了,感兴趣的小伙伴可以自行去官网下载React源码来看看。createElement(type, config, children)
在这里我就简述一下它的作用:
(1)在调用createElement方法之后,会先处理key、ref、self、source属性;
(2)接着就是config属性的处理,此时会调用hasOwnProperty方法处理除了对象原型、RESERVED_PROPS(key、ref)上面的属性,将其拷贝到props对象中;
(3)处理createElement第三个参数以及第三个参数之后情况,当createElement形参只有三个时,将第三个参数直接赋值给children,当createElement形参大于三个时,遍历第三个参数及之后参数到一个新的数组中,然后赋值给children;
(4)接着查看type.defaultPorps是否存在,如果存在的话且在props中找到其对应字段的值为undefined时,就将其存入到props中;
(5)最后将处理完的数据作为参数返回给ReactElement
方法中,其实这个ReactElement方法就是一个虚拟dom节点。
ReactElement方法又做了什么处理?该方法就是我们所说的虚拟dom节点,它其实就是又把我们处理过的数据再进行了一次组合,比较特殊的是它在这里添加了$$typeof
属性,然后最后返回element对象。
提到$$typeof属性,在这里延展一下为什么要使用它:其实$$typeof它的值是Symbol类型的,这样做的原因是因为服务器存在使用JSON作为文本返回的安全漏洞问题,也就是我们常常所说的xss跨站脚本攻击,这个时候由于JSON不支持Symbol类型,所以在虚拟dom中添加$$typeof使用Symbol标记我们的每一个React元素,React就会去检测每一个元素的$$typeof,如果该元素丢失或者无效就会拒绝处理该元素。
在第一节中我们大致了解了createElement和ReactElement两个方法的过程,下面就来实现一下如何写一个简版的虚拟dom对象。在这里我们就只处理props和type,至于key、ref等字段你可以看完源码自己封装一波图片图片。
1 | // 虚拟dom中的一个节点 |
得到element对象结果值如下图所示:
封装的element对象返回值