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,所以這個工作我們就需要自己來。

當然這又是另一個工作了,這些其他的部分,怎麼給它擰出來,也是需要去做的。

所以目前來說,後面就都是一些勞動量的問題了,最主要的問題,我們已經解決完了。

 

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