JavaScript进阶(三十八):如何拆解一个表达式(三)

上篇博客,我们得到表达式的内容了,那么接下来我们想干什么?是不是想把挑出来的这段表达式,给它解析了呀?

我们在之前的博客中也有做过,用的是 eval。

首先肯定一点,其实也没什么特别高明的办法,要么 eval,要么就 function,就这两种办法。

不过现在,我们准备重新的再来这一下这个事,为什么呢?

首先,在我们编译 s 这个字符串的过程当中,别的都可以忽略,但起码得有数据吧?

那么这个 VText,它身上有数据吗?并没有。

那谁身上有?是不是 VComponent 身上有,所有的数据都在 VComponent 身上。相当于不管是 VElement,还是 VNode,它们其实都是没有数据的状态,都是一个纯节点。

那么如果想要数据,就得找 VComponent,所以这时候,我们就得知道,这个节点它所对应的那个 component 是谁。

 

那么我们就直接来了,对于 VText 和 VElement 它们两个来说,我们还需要一个额外的参数。

什么参数呢?那就是我的 component 是谁:

因为如果不知道这个的话,其实是很费劲的。

然后这个 component 需要做几件事:

首先,我们 assert 一下,你必须得给我,你不给我就干不了活,因为数据都没,啥都做不了。

然后我们要把它给存起来:

以及 VElement 这边,我们也需要 component ,因为你得告诉我,我属于谁,然后我在借助它的数据,去编译我的东西:

当然,如果在这时候我们直接就这么运行,是会报错的:

其实就是 VText 这边报的,因为我们并没有传 component,那这个怎么办呢?

非常简单,首先我们别忘了,VText 是谁创建出来的?其实 VText 是 VElement 创建出来的,为什么这么说呢?

因为我们 VElement 里面的 createChildren,它是要递归的往里面创建的,并且它在递归的过程当中,是不是顺便的就把我们的那个 VText 也创建出来了。

所以说白了,它是从 VElement 里面来的。

 

所以在这种情况下,事情就变的非常的好办,我们就可以在 createChildren 里面,给它加个参数:

并且,分别传给我的子元素 VElement,和子文本元素 VText:

当然这时候又有一个问题了,你可以看到页面上还是报错:

这回的报错,其实是 VElement,因为我们现在并没有 component 这个东西。

如果我们在 VElement 里面也做个 assert,你就可以清楚的看到了。

因为我们往下面传,是没问题的,但是首先,我自己得有这个 component,不然我都没有,怎么往下传呢。

那这时候怎么办,我怎么样才能给它加上呢?其实特别的简单。

大家别忘了,我们的 VComponent 是哪来的?是不是继承自 VElement 的:

并且,在这个 VComponent 里面,它的 super 这里,我们要先搞清楚一个问题,在这,谁是组件?

比如现在,我想调父级,这里的 super 对应的是不是就是 VElement?

那谁是组件?

其实就是我自己,VComponent 它自己就是组件。

那么在这种情况下,我们就可以这么来写。

但是,你仍然可以看到页面上的报错:

它说,你在调用 super 之前,不能用 this,这就是一个鸡生蛋还是蛋生鸡的问题。

所以,现在这里不能放 this,因为这个时候,super 还没执行完:

但是我创建的时候,确实又需要 this,那怎么办呢?

其实我们可以用一个特别简单的办法来解决这个问题。

 

现在只有一种人,是无须提供 component,就能直接用的,这种人是谁?

这种人是谁?就是我自己,我自己就是 component。

所以我们 VElement 这里就不做 assert 了,因为我自己,我这个VElement,有可能就是一个 component:

那我怎么知道我是不是 component?

很简单,那就得看看,是不是继承出来的。

然后这个 component 有可能是空的,那如果是空的,我就用 this,因为我是一个 component:

那么你可以看到,这个时候,页面上就没有报错了:

所以我们这个 component 的引用就算是好了。

然后我们把 cmp 打印出来看看,看看它的子级:

你可以看到,第一个子级是个 VElement,并且,它里面有一个组件 _component。

这个组件是谁?你可以看到,就是我的父级,div#root。

包括下面的 VText 和 VElement,它们的 _component 也都是 div#root:

所以相当于现在,我是在用我未来的值,有点类似于高阶类。

实际上来说,我自己有可能是个 VComponent,那我就用自己就好了。

当然,如果我提供了 component 就用,没提供就用我自己,说明我自己就是顶层。

因为我自己是没有父级的,就这么简单。

 

这个东西稍微有点绕,首先,我们的最外层就是一个 VComponent,因为我们写的就是 let cmp = new VComponent({...})。

其实说白了,所有人引的都是最外层的它。

当然这个所有人,也包括它自己,它自己的 component 引用,就是它自己。

 

那为什么会有这样的一个状态呢?很简单。

你别看我是 VComponent,没错,确实有点特殊,但我也是一个 VElement,因为 VComponent extends VElement。

就是说,首先我是一个 VElement,然后其次我才是一个 VComponent。

所以这里面稍微有一点容易乱的地方就在于:不光最外层它里面的那些东西 VElement、VText,它们都需要引我,这个大家肯定能理解,还有一点就是,我自己也要引我自己。

说的直白一点,我们写的 let cmp = new VComponent({...}) 的这个 VComponent,它对应的其实就是最外层的 div:

根节点对应着根组件,很正常。

所以在这里面有一个问题,就是我自己的父级,就是我自己,因为已经到头了。

 

所以,除了我下面的那些子元素得找我,因为它们自己没有数据,我有,所以它们肯定得找我。

然后除了它们找我之外,我自己也要找我自己。

因为我自己,也就是最外层的这个根元素,也需要一些数据,比如像这些:

我也是需要数据的,这没办法。

 

所以在这种情况下,这个 component,它有可能有值:

为什么可能有值呢?

因为我们在 createChildren 的时候,会传一个 component:

我们有可能传值了,也有可能没传值。

所以在下面,理论上我们就可以做一个判断,如果 component 是有值的,那么 this._component 就是 component:

这个相信大家绝对能理解,但是不太好理解的就是 else。

else 如果没有值,说明我就是顶层,所以才没人给我。

所以在这时候,既然我就是顶级,那我就可以断定,我自己是个 VComponent。

我们可以来试试,在 else 里面我们来 console 一下:

这个时候,你可以看到,就是 true。

当然,在别的级别里面,比如 VElement 和 VText,如果我们也 console 的话,看看它们是不是 VComponent:

你可以看到,都是 false,就我一个人是 true。

所以说白了,有一个元素是很特殊的,就是最外层的那个元素 div#root。

那么它特殊在哪?特殊在它没有父级,它自己就是那个根,这就意味着它就有两重身份,它既是一个 VElement 标签元素,同时它也是一个 VComponent 组件。

当然,为什么它是个 VComponent 组件,因为我们在里面的 super 会执行到 VElement 那去。

所以说白了,我们在 VElement 这里就要判断一下,有人给我传,那挺好。

没人给我传怎么办?那我就要自己解决。

所以在 else 的时候,我的 _component,就是我自己:

当然,把它作一个简写,就是下面的这个东西:

相信大家现在就能理解了。

那么接下来,我们在 VText 的编译过程当中,其实就已经不光是有这个 s 了,并且还有数据了。

那么这个数据从哪拿?就是从 this._component 里面的 _data:

那么现在这时候你可以看到,比如第一个 a,当我要编译 a 的时候,是不是后面的数据就已经给我了呀,下面也都是一样。

既然有了数据,那么我们是不是就可以通过 this._component._data[s] 来做?当然这样是没有办法适应表达式的,但没关系,我们知道怎么做就行,一步步来。

然后我们是不是应该把 this._component._data[s] 这个值给存起来,并且让它拿去替换掉它原来的那个页面里的那堆东西。

以前的博客中,我们是用 replace 做的,而现在我们没用 replace,所以这个工作我们就需要自己来。

当然这又是另一个工作了,这些其他的部分,怎么给它拧出来,也是需要去做的。

所以目前来说,后面就都是一些劳动量的问题了,最主要的问题,我们已经解决完了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章