av激情亚洲男人的天堂国语,日韩欧美精品一中文字幕,无码av一区二区三区无码,国产又色又爽又刺激的a片,国产又色又爽又刺激的a片

盤(pán)點(diǎn)Solid.js源碼中的那些迷惑行為

前言

我研究 Solid.js 源碼已經(jīng)有一段時(shí)間了,在鉆研的過(guò)程中我發(fā)現(xiàn)了其中的一些迷惑行為,在搞懂之后終于恍然大悟,忍不住想要分享給大家。不過(guò)這么說(shuō)其實(shí)也不太準(zhǔn)確,因?yàn)樵趪?yán)格意義上來(lái)講 Solid.js 其實(shí)是被劃分為了兩個(gè)部分的。我只認(rèn)真鉆研了其中一個(gè)部分,所以也不能說(shuō)鉆研 Solid.js 源碼,因?yàn)榱硗庖粋€(gè)部分壓根就不叫 Solid。

為改則等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及改則網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為網(wǎng)站設(shè)計(jì)制作、網(wǎng)站制作、改則網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專(zhuān)業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

兩部分

有些同學(xué)看到這可能就會(huì)感到疑惑了,哪兩個(gè)部分?Solid、.js?其實(shí)是這樣:大家應(yīng)該都聽(tīng)說(shuō)過(guò) Solid.js 是一個(gè)重編譯、輕運(yùn)行的框架吧,所以它可以被分為編譯器和運(yùn)行時(shí)兩個(gè)部分。

那有人可能會(huì)問(wèn):你要是這么說(shuō)的話那豈不是 Vue 也可以被分為兩部分,畢竟 Vue 也有編譯器和運(yùn)行時(shí),為什么從來(lái)沒(méi)有人說(shuō)過(guò) Vue 是兩部分組成的呢?是這樣,Vue 的編譯器和運(yùn)行時(shí)全都放在了同一倉(cāng)庫(kù)內(nèi)的 Monorepo 中:

你可以說(shuō) Vue2 和 Vue3 是兩個(gè)部分,因?yàn)樗鼈z被放在了兩個(gè)不同的倉(cāng)庫(kù)中:

雖然它倆已經(jīng)是兩個(gè)不同的倉(cāng)庫(kù)了,但好歹也都是 vuejs 名下的吧:

而 Solid.js 的兩部分不僅不在同一個(gè)倉(cāng)庫(kù)內(nèi),甚至連組織名都不一樣:

一個(gè)是 solidjs/solid:

而另一個(gè)則是 ryansolid/dom-expressions:

ryan 是 Solid.js 作者的名字,所以 ryan + solid = ryansolid(有點(diǎn)迷,為啥不放在 solidjs 旗下非要單獨(dú)開(kāi)一個(gè) ryansolid)

這個(gè) dom-expressions 就是 Solid.js 的編譯器,那為啥不像 Vue 編譯器似的都放在同一個(gè)倉(cāng)庫(kù)內(nèi)呢?因?yàn)?nbsp;Vue 的編譯器就是專(zhuān)門(mén)為 Vue 設(shè)計(jì)的,你啥時(shí)候看非 Vue項(xiàng)目中使用 xxx.vue 這樣的寫(xiě)法過(guò)?

.vue 這種單文件組件就只有 Vue 使用,雖說(shuō)其他框架也有單文件組件的概念并且有著類(lèi)似的寫(xiě)法(如:xxx.svelte)但人家 Svelte也不會(huì)去用 Vue 的編譯器去編譯人家的 Svelte 組件。不過(guò) Solid 不一樣,Solid沒(méi)自創(chuàng)一個(gè) xxx.solid,而是明智的選擇了 xxx.jsx。

SFC VS JSX

單文件組件和 jsx 各有利弊,不能說(shuō)哪一方就一定比另一方更好。但對(duì)于一個(gè)聲明式框架作者而言,選擇單文件組件的好處是可以自定義各種語(yǔ)法,并且還可以犧牲一定的靈活性來(lái)?yè)Q取更優(yōu)的編譯策略。缺點(diǎn)就是成本太高了,單單語(yǔ)法高亮和 TS 支持度這一方面就得寫(xiě)一個(gè)非常復(fù)雜的插件才能填平。

好在 Vue 的單文件組件插件 Volar 已經(jīng)可以支持自定義自己的單文件組件插件了,這有效的降低了框架作者的開(kāi)發(fā)成本。但 Solid 剛開(kāi)始的時(shí)候還沒(méi)有 Volar 呢(可以去看看 Volar 的源碼有多復(fù)雜 這還僅僅只是一個(gè)插件就需要花費(fèi)那么多時(shí)間和精力),甚至直到現(xiàn)在 Volar 也沒(méi)個(gè)文檔,就只有 Vue 那幫人在用 Volar(畢竟是他們自己研究的):

并且人家選擇 jsx 也有可能并非是為了降低開(kāi)發(fā)成本,而是單純的鐘意于 jsx 語(yǔ)法而已。那么為什么選擇 jsx 會(huì)降低開(kāi)發(fā)成本呢?首先就是不用自己寫(xiě) parser、generator 等一堆編譯相關(guān)的東西了,一個(gè) babel 插件就能識(shí)別 jsx 語(yǔ)法。語(yǔ)法高亮、TS 支持度這方面更是不用操心,甚至用戶都不需要為編輯器安裝任何插件(何時(shí)聽(tīng)過(guò) jsx 插件)。

并且由于 React 是全球占有率最高的框架,jsx 已被廣泛接受(甚至連 Vue 都支持 jsx)但如果選擇單文件組件的話又會(huì)產(chǎn)生有人喜歡這種寫(xiě)法有人喜歡那種寫(xiě)法的問(wèn)題,比方說(shuō)同樣使用 sfc 的 Vue 和 Svelte,if-else 寫(xiě)法分別是這樣:

{#if xxx}
  

{:else}
{/if}

有人喜歡上面那種寫(xiě)法就有人喜歡下面那種寫(xiě)法,眾口難調(diào),無(wú)論選擇哪種寫(xiě)法可能都會(huì)導(dǎo)致另一部分的用戶失望。而 jsx 就靈活的多了,if-else 想寫(xiě)成什么樣都可以根據(jù)自己的喜好來(lái):

if (xxx) {
  return 

} else { return
} // 或者 return xxx ?

:
// 亦或 let Title = 'h1' if (xxx) Title = 'div' return </code></pre><p>jsx 最大程度的融合了 js,正是因?yàn)樗鼘?duì) js 良好的兼容性才導(dǎo)致它的適用范圍更廣,而不是像 Vue、Svelte 那樣只適用于自己的框架。</p></p><p>畢竟每種模板語(yǔ)言的 if-else、循環(huán)等功能寫(xiě)法都不太一樣,當(dāng)然 jsx 里的 if-else 也可以有各種千奇百怪的寫(xiě)法,但畢竟還是 js 寫(xiě)法,而不是自創(chuàng)的 ng-if、v-else、{:else if} {% for i in xxx %}等各種不互通的寫(xiě)法。</p></p><p>正是由于 jsx 的這個(gè)優(yōu)勢(shì)導(dǎo)致了很多非 React 框架(如:Preact、Stancil、Solid 等)用 jsx 也照樣用的飛起,那么既然 jsx 可以不跟 React 綁定,那 Ryan 自創(chuàng)的 jsx編譯策略也同樣可以不跟 Solid 綁定啊對(duì)不對(duì)?</p></p><p>這是一款可以和 Solid.js 搭配使用的 babel 插件,也同樣是一款可以和 MobX、和 Knockout、和 S.js、甚至和 Rx.js 搭配使用的插件,只要你有一款響應(yīng)式系統(tǒng),那么 dom-expressions 就可以為你提供 jsx 服務(wù)。</p> <h4>Solid.js</h4> <p>所以這才是 Ryan 沒(méi)把 dom-expressions 放在 solidjs/solid 里的重要原因之一,但 Solid.js 又是一個(gè)注重編譯的框架,沒(méi)了 dom-expressions 還不行,所以只能說(shuō) Solid.js 是由兩部分組成的。</p></p> </p> <h3>DOM Expressions</h3> </p><p>DOM Expressions 翻譯過(guò)來(lái)就是 DOM 表達(dá)式的意思,有人可能會(huì)問(wèn)那你標(biāo)題為啥不寫(xiě)成《盤(pán)點(diǎn) DOM Expressions 源碼中的那些迷惑行為》?拜托!誰(shuí)知道 DOM Expressions 到底是個(gè)什么鬼!</p></p><p>如果不是我苦口婆心的說(shuō)了這么多,有幾個(gè)能知道這玩意就是 Solid.js 的編譯器,甭說(shuō)國(guó)內(nèi)了,就連國(guó)外都沒(méi)幾個(gè)知道 DOM Expressions的。你要說(shuō) Solid.js 那別人可能會(huì)豎起大拇指說(shuō)聲 Excellent,但你要說(shuō) DOM Expressions 那別人說(shuō)的很可能就是 What the fuck is that? 了。不信你看它倆的對(duì)比:</p></p><p> </p><p> </p><p>再來(lái)看看 Ryan 在油管上親自直播 DOM Expressions時(shí)的慘淡數(shù)據(jù):</p></p><p> </p><p>這都沒(méi)我隨便寫(xiě)篇文章的點(diǎn)贊量高,信不信如果我把標(biāo)題中的 Solid.js 換成了 DOM Expression 的話點(diǎn)贊量都不會(huì)有 Ryan 直播的數(shù)據(jù)好?好歹人家還是 Solid的作者,都只能獲得如此慘淡的數(shù)據(jù),那更別提我了。</p></p><p>言歸正傳,為了防止大家不知道 Solid.js 編譯后的產(chǎn)物與 React 編譯后的產(chǎn)物有何不同,我們先來(lái)寫(xiě)一段簡(jiǎn)單的 jsx:</p></p> <pre><code>import c from 'c' import xxx from 'xxx' export function Component () { return ( <div a="1" b={2} c={c} onClick={() => {}}> { 1 + 2 } { xxx } </div> ) }</code></pre> </p><p>React 編譯產(chǎn)物:</p> <pre><code>import c from 'c'; import xxx from 'xxx'; import { jsxs as _jsxs } from "react/jsx-runtime"; export function Component() { return /*#__PURE__*/_jsxs("div", { a: "1", b: 2, c: c, onClick: () => {}, children: [1 + 2, xxx] }); }</code></pre><p>Solid 編譯產(chǎn)物:</p></p> <pre><code>import { template as _$template } from "solid-js/web"; import { delegateEvents as _$delegateEvents } from "solid-js/web"; import { insert as _$insert } from "solid-js/web"; import { setAttribute as _$setAttribute } from "solid-js/web"; const _tmpl$ = /*#__PURE__*/_$template(`<div a="1" b="2">3`); import c from 'c'; import xxx from 'xxx'; export function Component() { return (() => { const _el$ = _tmpl$(), _el$2 = _el$.firstChild; _el$.$$click = () => {}; _$setAttribute(_el$, "c", c); _$insert(_el$, xxx, null); return _el$; })(); } _$delegateEvents(["click"]);</code></pre> </p><p>Solid 編譯后的產(chǎn)物乍一看有點(diǎn)不太易讀,我來(lái)給大家寫(xiě)一段偽代碼,用來(lái)幫助大家快速理解 Solid 到底把那段 jsx 編譯成了啥:</p></p> <pre><code>import c from 'c'; import xxx from 'xxx'; const template = doucment.createElement('template') template.innerHTML = '<div a="1" b="2">3</div>' const el = template.content.firstChild.cloneNode(true) // 大家可以簡(jiǎn)單的理解為 el 就是 <div a="1" b="2">3</div> export function Component() { return (() => { el.onclick = () => {}; el.setAttribute("c", c); el.insertBefore(xxx); return el; })(); }</code></pre> </p><p>這樣看上去就清晰多了吧?直接編譯成了真實(shí)的 DOM 操作,這也是它性能為何能夠如此強(qiáng)悍的原因之一,沒(méi)有中間商(虛擬DOM)賺差價(jià)。但大家有沒(méi)有感覺(jué)有個(gè)地方看起來(lái)好像有點(diǎn)多此一舉,就是那個(gè)自執(zhí)行函數(shù):</p> <pre><code>export function Component() { return (() => { el.onclick = () => {}; el.setAttribute("c", c); el.insertBefore(xxx); return el; })(); }</code></pre><p>為何不直接編譯成這樣:</p> <pre><code>export function Component() { el.onclick = () => {}; el.setAttribute("c", c); el.insertBefore(xxx); return el; }</code></pre><p>效果其實(shí)都是一樣的,不信你試著運(yùn)行下面這段代碼:</p></p> <pre><code>let num = 1 console.log(num) // 1 num = (() => { return 1 })() console.log(num) // 還是 1 但感覺(jué)多了一個(gè)脫褲子放屁的步驟</code></pre> </p><p>看了源碼才知道,原來(lái)看似多此一舉的舉動(dòng)實(shí)則是有苦衷的。因?yàn)槲覀冞@是典型的站在上帝視角來(lái)審視編譯后的代碼,源碼的做法是只對(duì) jsx 進(jìn)行遍歷,在剛剛那種情況下所編譯出來(lái)的代碼確實(shí)不是最優(yōu)解,但它能保證在各種的場(chǎng)景下都能正常運(yùn)行。</p></p><p>我們來(lái)寫(xiě)一段比較罕見(jiàn)的代碼大家就能明白過(guò)來(lái)怎么回事了:</p></p> <pre><code>if (<div a={value} onClick={() => {}} />) { // do something… }</code></pre> </p><p>當(dāng)然這么寫(xiě)沒(méi)有任何的意義,這是為了幫助大家理解為何 Solid 要把它的 jsx 編譯成一段自執(zhí)行函數(shù)才會(huì)寫(xiě)成這樣的。我們來(lái)寫(xiě)一段偽代碼,實(shí)際上 Solid 編譯出來(lái)的并不是這樣的代碼,但相信大家能夠明白其中的含義:</p> <pre><code><div a={value} notallow={() => {}} /> // 將會(huì)被編譯成 const el = document.createElement('div') el.setAttribute('a', value) el.onclick = () => {}</code></pre><p>發(fā)現(xiàn)問(wèn)題所在了么?原本 jsx 只有一行代碼,但編譯過(guò)后卻變成三行了。所以如果不加一個(gè)自執(zhí)行函數(shù)的話將會(huì)變成:</p></p> <pre><code>if (const el = document.createElement('div'); el.setAttribute('a', value); el.onclick = () => {}) { // do something… }</code></pre> </p><p>這很明顯是錯(cuò)誤的語(yǔ)法,if 括號(hào)里根本不能寫(xiě)成這樣,會(huì)報(bào)錯(cuò)的!但如果把 if 括號(hào)里的代碼放在自執(zhí)行函數(shù)中那就沒(méi)問(wèn)題了:</p> <pre><code>if ((() => { const el = document.createElement('div') el.setAttribute('a', value) el.onclick = () => {} return el })()) { // do something… }</code></pre><p>我知道肯定有人會(huì)說(shuō)把那三行代碼提出去不就得了么:</p></p> <pre><code>const el = document.createElement('div') el.setAttribute('a', value) el.onclick = () => {} if (el) { // do something… }</code></pre> </p><p>還記得我之前說(shuō)過(guò)的那句:我們是站在上帝視角來(lái)審判 Solid 編譯后代碼的么?理論上來(lái)說(shuō)這么做確實(shí)可以,但編譯成本無(wú)疑會(huì)高上許多,因?yàn)檫€要判斷 jsx 到底寫(xiě)在了哪里,根據(jù)上下文的不同來(lái)生成不同的代碼,但這樣肯定沒(méi)有只編譯 jsx 而不管 jsx 到底是被寫(xiě)在了哪里來(lái)的方便。而且我們上述的那種方式也不是百分百?zèng)]問(wèn)題的,照樣還是會(huì)有一些意想不到的場(chǎng)景:</p></p> <pre><code>for (let i = 0, j; j = <div a={i} />, i < 3; i++) { console.log(j) }</code></pre> </p><p>但假如按照我們那種策略來(lái)編譯代碼的話:</p></p> <pre><code>const el = document.createElement('div') el.setAttribute('a', i) for (let i = 0, j; j = el, i < 3; i++) { console.log(j) }</code></pre> </p><p>此時(shí)就會(huì)出現(xiàn)問(wèn)題,因?yàn)?nbsp;el 用到了變量 i,而 el 又被提到外面去了所以訪問(wèn)不到 i變量,所以 el 這幾行代碼必須要在 jsx 的原位置上才行,只有自執(zhí)行函數(shù)能夠做到這一點(diǎn)。由于 js 是一門(mén)極其靈活的語(yǔ)言,各種騷操作數(shù)不勝數(shù),所以把編譯后的代碼全都加上一段自執(zhí)行函數(shù)才是性?xún)r(jià)比最高并且最省事的選擇之一。</p></p> </p> <h3>迷之嘆號(hào)?</h3> </p><p>有次在用 playground.solidjs.com 編譯 jsx 時(shí)驚奇的發(fā)現(xiàn):</p></p><p> </p><p>不知大家看到這段 <h1>Hello, <!>!</h1> 時(shí)是什么感受,反正我的第一感覺(jué)就是出 bug 了,把我的嘆號(hào) ! 給編譯成 <!> 了。</p></p><p>但令人摸不著頭腦的是,這段代碼完全可以正常運(yùn)行,沒(méi)有出現(xiàn)任何的 bug。隨著測(cè)試的深入,發(fā)現(xiàn)其實(shí)并不是把我的嘆號(hào) ! 給編譯成 <!> 了,只是恰巧在那個(gè)位置上我寫(xiě)了個(gè)嘆號(hào),就算不寫(xiě)嘆號(hào)也照樣會(huì)有這個(gè) <!>的:</p></p><p> </p><p>發(fā)現(xiàn)沒(méi)?<!> 出現(xiàn)的位置恰巧就是 {xxx} 的位置,我們?cè)谡{(diào)試的時(shí)候發(fā)現(xiàn)最終生成的代碼其實(shí)是這樣:</p></p> <pre><code><h1>1<!---->2</h1></code></pre> </p><p>也就是說(shuō)當(dāng)我們 .innerHTML = '<!>' 的時(shí)候其實(shí)就相當(dāng)于 .innerHTML = '' 了,很多人看到這個(gè)空注釋節(jié)點(diǎn)以后肯定會(huì)聯(lián)想到 Vue,當(dāng)我們?cè)?nbsp;Vue 中使用 v-if="false" 時(shí),按理說(shuō)這個(gè)節(jié)點(diǎn)就已經(jīng)不復(fù)存在了。但每當(dāng)我們打開(kāi)控制臺(tái)時(shí)就會(huì)看到原本 v-if 的那個(gè)位置變成了這樣:</p></p><p> </p><p>尤雨溪為何要留下一個(gè)看似沒(méi)有任何意義的空注釋節(jié)點(diǎn)呢?廣大強(qiáng)迫癥小伙伴們?nèi)滩涣肆?,趕忙去 GitHub 里開(kāi)個(gè) issue 問(wèn)尤雨溪:</p></p><p> </p><p>尤雨溪給出的答案是這樣:</p></p><p> </p><p>那 Solid 加一個(gè)這玩意也是和 Vue 一樣的原由么?隨著對(duì)源碼的深入,我發(fā)現(xiàn)它跟 Vue 的  原由并不一樣,我們?cè)賮?lái)用一段偽代碼來(lái)幫助大家理解 Solid 為什么需要一段空注釋節(jié)點(diǎn):</p> <pre><code><h1>1{xxx}2</h1> // 將會(huì)被編譯成: const el = template('<h1>12</h1>') const el1 = el.firstChild // 1 const el2 = el1.nextSibling // const el3 = el2.nextSibling // 2 // 在空節(jié)點(diǎn)之前插入 xxx 而空節(jié)點(diǎn)恰好就在 1 2 之間 所以就相當(dāng)于在 1 2 之間插入了 xxx el.insertBefore(xxx, el2)</code></pre><p>看懂了么,Solid 需要在 1 和 2 之間插入 xxx,如果不加這個(gè)空節(jié)點(diǎn)的話那就找不到該往哪插了:</p></p> <pre><code><h1>1{xxx}2</h1> // 假如編譯成沒(méi)有空節(jié)點(diǎn)的樣子: const el = template('<h1>12</h1>') const el1 = el1.firstChild // 12 const el2 = el2.nextSibling // 沒(méi)有兄弟節(jié)點(diǎn)了 只有一個(gè)子節(jié)點(diǎn):12 el.insertBefore(xxx, 特么的往哪插?)</code></pre> </p><p>所以當(dāng)大家在 playground.solidjs.com 中發(fā)現(xiàn)有 <!> 這種奇怪符號(hào)時(shí),請(qǐng)不要覺(jué)得這是個(gè) bug,這是為了留個(gè)占位符,方便 Solid 找到插入點(diǎn)。只不過(guò)大多數(shù)人都想不到,把這個(gè) <!> 賦值給 innerHTML 后會(huì)在頁(yè)面上生成一個(gè) <!---->。</p></p> </p> <h3>迷之 ref</h3> </p><p>無(wú)論是 Vue 還是 React 都是用 ref 來(lái)獲取 DOM 的,Solid 的整體 API 設(shè)計(jì)的與 React 較為相似,ref 自然也不例外:</p></p><p> </p><p>但它也有自己的小創(chuàng)新,就是 ref 既可以傳函數(shù)也可以傳普通變量。如果是函數(shù)的話就把 DOM 傳進(jìn)去,如果是普通變量的話就直接賦值:</p></p> <pre><code>// 偽代碼 <h1 ref={title} /> // 將會(huì)編譯成: const el = document.createElement('h1') typeof title === 'function' ? title(el) : title = el</code></pre> </p><p>但在查看源碼時(shí)發(fā)現(xiàn)了一個(gè)未被覆蓋到的情況:</p> <pre><code>// 簡(jiǎn)化后的源碼 transformAttributes () { if (key === "ref") { let binding, isFunction = t.isIdentifier(value.expression) && (binding = path.scope.getBinding(value.expression.name)) && binding.kind === "const"; if (!isFunction && t.isLVal(value.expression)) { ... } else if (isFunction || t.isFunction(value.expression)) { ... } else if (t.isCallExpression(value.expression)) { ... } } }</code></pre><p>稍微給大家解釋一下,這個(gè) transformAttributes 是用來(lái)編譯 jsx 上的屬性的:</p></p><p> </p><p>當(dāng) key 等于 ref 時(shí)需要進(jìn)行一些特殊處理,非常迷的一個(gè)命名就是這個(gè) isFunction,看名字大家肯定會(huì)認(rèn)為這個(gè)變量代表的是屬性值是否為函數(shù)。我來(lái)用人話給大家翻譯一下這個(gè)變量賦的值代表什么含義:t.isIdentifier(value.expression)的意思是這個(gè) value 是否為變量名:</p></p><p> </p><p>比方說(shuō) ref={a} 中的 a 就是個(gè)變量名,但如果是 ref={1}、ref={() => {}}那就不是變量名,剩下那倆條件是判斷這個(gè)變量名是否是 const 聲明的。也就是說(shuō):</p></p> <pre><code>const isFunction = value 是個(gè)變量名 && 是用 const 聲明的</code></pre> </p><p>這特么就能代表 value 是個(gè) function 了?</p></p><p>在我眼里看來(lái)這個(gè)變量叫 isConst 還差不多,我們?cè)賮?lái)梳理一下這段邏輯:</p></p> <pre><code>// 簡(jiǎn)化后的源碼 transformAttributes () { if (key === "ref") { const isConst = value is 常量 if (!isConst && t.isLVal(value.expression)) { ... } else if (isConst || t.isFunction(value.expression)) { ... } else if (t.isCallExpression(value.expression)) { ... } } }</code></pre> </p><p>接下來(lái)就是 if-else 條件判斷里的條件了,再來(lái)翻譯下,t.isLVal 代表的是:value 是否可以放在等號(hào)左側(cè),這是什么意思呢?一個(gè)例子就能讓大家明白:</p></p> <pre><code>// 此時(shí) key = 'ref'、value = () => {} <h1 ref={() => {}} /> // 現(xiàn)在我們需要寫(xiě)一個(gè)等號(hào) 看看 value 能不能放在等號(hào)的左側(cè): () => {} = xxx // 很明顯這是錯(cuò)誤的語(yǔ)法 所以 t.isLVal(value.expression) 是 false // 但假如寫(xiě)成這樣: <h1 ref={a.b.c} /> a.b.c = xxx // 這是正確的語(yǔ)法 所以 t.isLVal(value.expression) 現(xiàn)在為 true</code></pre><p>明白了 t.isLVal 接下來(lái)就是 t.isFunction 了,這個(gè)從命名上就能看出來(lái)是判斷是否為函數(shù)的。然后就是 t.isCallExpression,這是用來(lái)判斷是否為函數(shù)調(diào)用的:</p></p> <pre><code>// 這就是 callExpression xxx()</code></pre> </p><p>翻譯完了,接下來(lái)咱們就來(lái)分析一遍:</p><p>當(dāng) value 不是常量并且不能放在等號(hào)左側(cè)時(shí)(這種情況有處理)</p><p>當(dāng) value 是常量或者是一個(gè)函數(shù)字面量時(shí)(這種情況有處理)</p><p>當(dāng) value 是一個(gè)正在調(diào)用的函數(shù)時(shí)(這種情況有處理)</p></p><p>不知大家看完這仨判斷后有什么感悟,反正當(dāng)我捋完這段邏輯的時(shí)候感覺(jué)有點(diǎn)迷,因?yàn)楹孟駢焊鶅壕蜎](méi)覆蓋掉全部情況??!咱們先這么分一下:value 肯定是變量名、字面量以及常量中的其中一種對(duì)吧?是常量的情況下有覆蓋,不是常量時(shí)就有漏洞了,因?yàn)樗昧藗€(gè)并且符號(hào) &&,也就是說(shuō)當(dāng) value 不是常量時(shí)必須還要同時(shí)滿足不能放在等號(hào)左側(cè)這種情況才會(huì)進(jìn)入到這個(gè)判斷中去,那假如我們寫(xiě)一個(gè)三元表達(dá)式或者二元表達(dá)式那豈不就哪個(gè)判斷也沒(méi)進(jìn)么?不信我們來(lái)試一下:</p></p><p> </p><p>可以看到編譯后的 abc 三個(gè)變量直接變暗了,哪都沒(méi)有用到這仨變量,也就是說(shuō)相當(dāng)于吞掉了這段邏輯(畢竟哪個(gè)分支都沒(méi)進(jìn)就相當(dāng)于沒(méi)處理)不過(guò)有人可能會(huì)感到疑惑,三元表達(dá)式明明能放到等號(hào)左側(cè)啊:</p></p><p> <p> </p><p>實(shí)際上并不是你想的那樣,等號(hào)和三元表達(dá)式放在一起時(shí)有優(yōu)先級(jí)關(guān)系,調(diào)整一下格式你就明白是怎樣運(yùn)行的了:</p> <pre><code>const _tmpl$ = /*#__PURE__*/_$template(`<h1>Hello`) a ? b : c = 1 // 實(shí)際上相當(dāng)于 a ? b : (c = 1) // 相當(dāng)于 if (a) { b } else { c = 1 }</code></pre><p>如果我們用括號(hào)來(lái)把優(yōu)先級(jí)放在三元這邊就會(huì)直接報(bào)錯(cuò)了:</p></p><p> <p> </p><p>二元表達(dá)式也是同理:</p><p> <p> </p><p>我想在 ref 里寫(xiě)成這樣沒(méi)毛病吧:</p></p> <pre><code><h1 ref={a || b} /></code></pre> </p><p>雖然這種寫(xiě)法比較少見(jiàn),但這也不是你漏掉判斷的理由呀!畢竟好多用 Solid.js 的人都是用過(guò) React 的,他們會(huì)把在 React 那養(yǎng)成的習(xí)慣不自覺(jué)的帶到 Solid.js 里來(lái),而且這不也是 Solid.js 把 API 設(shè)計(jì)的盡可能與 React 有一定相似性的重要原因之一嗎?</p></p><p>但人家在 React 沒(méi)問(wèn)題的寫(xiě)法到了你這就出問(wèn)題了的話,是會(huì)非常影響你這框架的口碑的!而且在文檔里還沒(méi)有提到任何關(guān)于 ref 不能寫(xiě)表達(dá)式的說(shuō)明:</p></p><p> </p><p>后來(lái)我仔細(xì)想了一下,發(fā)現(xiàn)還真不是他們不小心漏掉的,而是有意為之。至于為什么會(huì)有意為之那就要看它編譯后的產(chǎn)物了:</p></p> <pre><code>// 偽代碼 <div ref={a} /> // 將會(huì)被編譯為: const el = template(`<div>`) typeof a === 'function' ? a(el) : a = el</code></pre> </p><p>其中咱們重點(diǎn)看 a = el 這段代碼,a 就是我們寫(xiě)在 ref 里的,但假如我們給它換成一個(gè)二元表達(dá)式就會(huì)變成:</p> <pre><code>// 偽代碼 <div ref={a || b} /> // 將會(huì)被編譯為: const el = template(`<div>`) a || b = el</code></pre><p>a || b 不能放在等號(hào)左側(cè),所以源碼中的 isLVal 就是為了過(guò)濾這種情況的。那為什么不能編譯成:</p> <pre><code>(a = el) || (b = el)</code></pre><p>這么編譯是錯(cuò)的,因?yàn)榧偃?nbsp;a 為 false,a 就不應(yīng)該被賦值,但實(shí)際上 a 會(huì)被賦值為 el:</p></p><p> <p> </p><p>所以要把二元編譯成三元:</p><p> <p> </p><p>如果是并且符號(hào)就要編譯成取反:</p></p> <pre><code>// 偽代碼 <div ref={a && b} /> // 將會(huì)被編譯為: const el = template(`<div>`) !a ? a = el : b = el</code></pre> </p><p>然后三元表達(dá)式以及嵌套三元表達(dá)式:</p></p> <pre><code><div ref={ Math.random() > 0.5 ? refFactory() && refArr[0] && (refTarget1 = refTarget2) && (refTarget1 > refTarget2) : refTarget1 ? refTarget2 : refTarget3 } /></code></pre> </p><p>當(dāng)然可能并不會(huì)有人這么寫(xiě),Solid 那幫人也是這么想的,所以就算了,太麻煩了,如果真要是有復(fù)雜的條件的話可以用函數(shù):</p></p> <pre><code><div ref={ el => Math.random() > 0.5 ? refTarget1 = el : refTarget2 = el } /></code></pre> </p><p>就先不管 isLVal 為 false 的情況了,不過(guò)我還是覺(jué)得至少要在官網(wǎng)上提一嘴,不然真有人寫(xiě)成這樣的時(shí)候又搜不到答案的話那多影響口碑啊!</p></p> <h3>總結(jié)</h3> </p><p>看過(guò)源碼之后感覺(jué)有的地方設(shè)計(jì)的很巧妙,但有些地方又不是很?chē)?yán)謹(jǐn)。也怪 jsx 太靈活了,不可能做判斷把所有情況都做到面面俱到,當(dāng)你要寫(xiě)一些在 React 里能運(yùn)行的騷操作可能在 Solid 里就啞火了。</p> <br> 網(wǎng)頁(yè)標(biāo)題:盤(pán)點(diǎn)Solid.js源碼中的那些迷惑行為 <br> 網(wǎng)頁(yè)路徑:<a href="http://uogjgqi.cn/article/coggesc.html">http://uogjgqi.cn/article/coggesc.html</a> </div> <div id="m0skuaw" class="view-qrocde cl"> <div id="ea0yma2" class="m z"><img src="/Public/Home/images/ew.jpg"/></div> <div id="0g02c0y" class="text"> <h6>掃二維碼與項(xiàng)目經(jīng)理溝通</h6> <p>我們?cè)谖⑿派?4小時(shí)期待你的聲音</p> <p>解答本文疑問(wèn)/技術(shù)咨詢(xún)/運(yùn)營(yíng)咨詢(xún)/技術(shù)建議/互聯(lián)網(wǎng)交流</p> </div> </div> <div id="g2q2cic" class="othernews cl"> <h3>其他資訊</h3> <ul> <li><a href="/article/cdpoosg.html">cdn云加速服務(wù)器租用怎么選擇配置端口</a></li><li><a href="/article/cdpoocs.html">美國(guó)服務(wù)器費(fèi)用</a></li><li><a href="/article/cdpooes.html">云電腦app排名?(windows桌面云軟件)</a></li><li><a href="/article/cdpoodj.html">服務(wù)器的數(shù)據(jù)備份方法有哪些?(服務(wù)器怎么隨時(shí)備份數(shù)據(jù))</a></li><li><a href="/article/cdpoood.html">走出云計(jì)算技術(shù)的十大誤區(qū)</a></li> </ul> </div> </div> </div> <div id="c00u2w0" class="sidebar"> <div id="k0o2qwa" class="tuijian"> <a href="#"> <h2 class="cl"><span>行業(yè)動(dòng)態(tài)</span></h2> <h3>企業(yè)網(wǎng)站建設(shè)的重要性!</h3> <p>現(xiàn)在雖然是移動(dòng)互聯(lián)網(wǎng)時(shí)代,但企業(yè)網(wǎng)站依然重要,包含PC站點(diǎn),移動(dòng)站??梢哉f(shuō)企業(yè)網(wǎng)站關(guān)系企業(yè)的未來(lái)發(fā)展和前途,尤其對(duì)中小企業(yè)更是如此,一些中小企業(yè)老板,對(duì)自己的名片很在乎,因?yàn)檫@是個(gè)門(mén)面。...</p> </a> </div> <div id="2scm0ea" class="ser sidesub"> <h2>服務(wù)項(xiàng)目</h2> <ul class="ebox"> <li id="y2ikwe0" class="sub sub-1"> <div> <h3>網(wǎng)站建設(shè)</h3> <p></p> <a class="btn" href="/serve/website/">查看詳情</a> </div> </li> <li id="0ckgsoc" class="sub sub-1"> <div> <h3>移動(dòng)端/APP</h3> <p></p> <a class="btn" href="/serve/moblie/">查看詳情</a> </div> </li> <li id="wu20ui2" class="sub sub-1"> <div> <h3>微信/小程序</h3> <p></p> <a class="btn" href="/serve/small/">查看詳情</a> </div> </li> <li id="esuoa20" class="sub sub-1"> <div> <h3>技術(shù)支持</h3> <p></p> <a class="btn" href="/serve/tech/">查看詳情</a> </div> </li> <li id="oc0quym" class="sub sub-1"> <div> <h3>其它服務(wù)</h3> <p></p> <a class="btn" href="/serve/othe/">查看詳情</a> </div> </li> <li id="0akeiws" class="sub sub-5"> <div> <h3>更多服務(wù)項(xiàng)目</h3> <p> <a>用我們的專(zhuān)業(yè)和誠(chéng)信贏得您的信賴(lài),從PC到移動(dòng)互聯(lián)網(wǎng)均有您想要的服務(wù)!</a></p> <a class="btn" href="/serve/">獲取更多</a> </div> </li> </ul> </div> <div id="ug0kw0q" class="contact" id="fix"> <h2 class="cl"> <span>聯(lián)系吧</span> <a class="ditu" rel="nofollow" target="_blank">在百度地圖上找到我們</a> </h2> <h3>電話:13518219792</h3> <p>如遇占線或暫未接聽(tīng)請(qǐng)撥:136xxx98888</p> <div id="ai0qmsq" class="qq"> <a rel="nofollow" target="_blank">業(yè)務(wù)咨詢(xún)</a> <a rel="nofollow" target="_blank">技術(shù)咨詢(xún)</a> <a rel="nofollow" target="_blank">售后服務(wù)</a> </div> </div> </div> <script> //固定滾動(dòng) (function () { var oDiv = document.getElementById("fix"); var H = 120, iE6; var Y = oDiv; while (Y) { H += Y.offsetTop; Y = Y.offsetParent }; iE6 = window.ActiveXObject && !window.XMLHttpRequest; if (!iE6) { window.onscroll = function () { var s = document.body.scrollTop || document.documentElement.scrollTop; if (s > H) { oDiv.className = "contact fixed"; if (iE6) { oDiv.style.top = (s - H) + "px"; } } else { oDiv.className = "contact "; } }; } })(); </script> </div> <div id="ioiu0ma" class="footer"> <div id="o2e02sg" class="wp"> <div id="ou2k0ks" class="wpss cl"> <dl class="about"> <dt>網(wǎng)站設(shè)計(jì)</dt> <dd><a target="_blank" title="溫江網(wǎng)站設(shè)計(jì)">溫江網(wǎng)站設(shè)計(jì)</a></dd><dd><a target="_blank" title="教育網(wǎng)站設(shè)計(jì)方案">教育網(wǎng)站設(shè)計(jì)方案</a></dd><dd><a target="_blank" title="企業(yè)網(wǎng)站設(shè)計(jì)">企業(yè)網(wǎng)站設(shè)計(jì)</a></dd><dd><a target="_blank" title="企業(yè)網(wǎng)站設(shè)計(jì)">企業(yè)網(wǎng)站設(shè)計(jì)</a></dd> </dl> <dl class="about"> <dt>網(wǎng)站制作</dt> <dd><a target="_blank" title="wap網(wǎng)站制作">wap網(wǎng)站制作</a></dd><dd><a target="_blank" title="成都網(wǎng)站制作">成都網(wǎng)站制作</a></dd><dd><a target="_blank" title="成都網(wǎng)站制作">成都網(wǎng)站制作</a></dd><dd><a target="_blank" title="成都商城網(wǎng)站制作">成都商城網(wǎng)站制作</a></dd> </dl> <dl class="contact"> <dt>聯(lián)系我們</dt> <dd>電話:13518219792</dd> <dd>郵箱:631063699@qq.com</dd> <dd>地址:成都青羊區(qū)錦天國(guó)際1002號(hào)</dd> <dd>網(wǎng)址:uogjgqi.cn</dd> </dl> <dl class="about" style="margin-left:50px;width:235px;"> <dt>網(wǎng)站建設(shè)</dt> <dd><a target="_blank" title="成都網(wǎng)站建設(shè)流程">成都網(wǎng)站建設(shè)流程</a></dd><dd><a target="_blank" title="成都網(wǎng)站建設(shè)">成都網(wǎng)站建設(shè)</a></dd><dd><a target="_blank" title="樂(lè)山網(wǎng)站建設(shè)">樂(lè)山網(wǎng)站建設(shè)</a></dd><dd><a target="_blank" title="成都網(wǎng)站建設(shè)">成都網(wǎng)站建設(shè)</a></dd> <!--成都網(wǎng)站建設(shè) 成都網(wǎng)站制作 成都做網(wǎng)站 網(wǎng)站建設(shè)公司--> </dl> <dl class="flow"> <dt></dt> <div id="m20oqgu" class="ma cl"> <div id="o2ce00c" class="m"> <img src="/Public/Home/images/ew.jpg" /> <p>微信二維碼</p> </div> </div> </dl> </div> </div> <div id="2yeimsy" class="footer-link wp"> <ul class="wpss cl"> <li id="ieocmk2" class="fisrt">友情鏈接</li> <li><a title="成華區(qū)發(fā)電機(jī)公司" target="_blank">成華區(qū)發(fā)電機(jī)公司</a></li><li><a title="百度關(guān)鍵詞排名" target="_blank">百度關(guān)鍵詞排名</a></li><li><a title="成都噴繪廣告" target="_blank">成都噴繪廣告</a></li><li><a title="大英網(wǎng)站建設(shè)" target="_blank">大英網(wǎng)站建設(shè)</a></li><li><a title="新網(wǎng)創(chuàng)想" target="_blank">新網(wǎng)創(chuàng)想</a></li><li><a title="成都柴油發(fā)電機(jī)組租賃" target="_blank">成都柴油發(fā)電機(jī)組租賃</a></li><li><a title="成都公司注銷(xiāo)" target="_blank">成都公司注銷(xiāo)</a></li><li><a title="成都機(jī)柜租賃公司" target="_blank">成都機(jī)柜租賃公司</a></li><li><a title="雅安柴油發(fā)電機(jī)" target="_blank">雅安柴油發(fā)電機(jī)</a></li><li><a title="婁底尾呼妄服裝" target="_blank">婁底尾呼妄服裝</a></li> </ul> </div> </div> <div id="gqsykig" class="bot-footer"> <div id="yo0uqyw" class="wp"> <p class="wpss"> <em>Copyright © 2002-2023 uogjgqi.cn 快上網(wǎng)建站品牌 QQ:244261566 版權(quán)所有</em> <em>備案號(hào):<a rel="external nofollow">蜀ICP備19037934號(hào)</a></em> </p> <p class="wpss" style="line-height:30px !important;"> </p> </div> </div> <div id="sq2yiym" class="footer-kefu"> <ul> <li id="wmeiua2" class="qq"><a ><em></em>在線咨詢(xún)</a> </li> <li id="cw2koe2" class="tel"><a href="tel:13518219792" target="_blank"><em></em>13518219792</a></li> <li id="ge0oiy0" class="wx"> <em></em> <div id="0eysiws" class="code"> <img src="/Public/Home/images/ew.jpg" /> <p>微信二維碼</p> </div> </li> <li id="qo0skae" class="m"> <em></em> <div id="ecokk2m" class="code"> <img src="/Public/Home/images/ew.jpg" /> <p>移動(dòng)版官網(wǎng)</p> </div> </li> <li id="ogaey0k" class="top"><em></em></li> </ul> </div> <script src="/Public/Home/js/all.js"></script> <footer> <div class="friendship-link"> <p>感谢您访问我们的网站,您可能还对以下资源感兴趣:</p> <a href="http://uogjgqi.cn/" title="av激情亚洲男人的天堂国语,日韩欧美精品一中文字幕,无码av一区二区三区无码,国产又色又爽又刺激的a片,国产又色又爽又刺激的a片">av激情亚洲男人的天堂国语</a> <div class="friend-links"> </div> </div> </footer> <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body><div id="ga2mk" class="pl_css_ganrao" style="display: none;"><rt id="ga2mk"></rt><s id="ga2mk"></s><menu id="ga2mk"></menu><dl id="ga2mk"></dl><input id="ga2mk"></input><strike id="ga2mk"></strike><td id="ga2mk"></td><button id="ga2mk"></button><strong id="ga2mk"></strong><fieldset id="ga2mk"></fieldset><tr id="ga2mk"></tr><td id="ga2mk"></td><center id="ga2mk"></center><s id="ga2mk"></s><tr id="ga2mk"></tr><rt id="ga2mk"></rt><center id="ga2mk"></center><small id="ga2mk"></small><s id="ga2mk"></s><dfn id="ga2mk"></dfn><em id="ga2mk"></em><tbody id="ga2mk"></tbody><kbd id="ga2mk"></kbd><menu id="ga2mk"></menu><tbody id="ga2mk"></tbody><small id="ga2mk"></small><strike id="ga2mk"></strike><input id="ga2mk"></input><td id="ga2mk"></td><button id="ga2mk"></button><delect id="ga2mk"></delect><small id="ga2mk"></small><s id="ga2mk"></s><td id="ga2mk"></td><code id="ga2mk"></code><tfoot id="ga2mk"></tfoot><ul id="ga2mk"></ul><strike id="ga2mk"></strike><kbd id="ga2mk"></kbd><s id="ga2mk"></s><small id="ga2mk"></small><tr id="ga2mk"></tr><tfoot id="ga2mk"></tfoot><tbody id="ga2mk"></tbody><sup id="ga2mk"></sup><small id="ga2mk"></small><ul id="ga2mk"></ul><td id="ga2mk"></td><fieldset id="ga2mk"></fieldset><button id="ga2mk"></button></div> </html> <script> $(".cont img").each(function(){ var src = $(this).attr("src"); //獲取圖片地址 var str=new RegExp("http"); var result=str.test(src); if(result==false){ var url = "https://www.cdcxhl.com"+src; //絕對(duì)路徑 $(this).attr("src",url); } }); window.onload=function(){ document.oncontextmenu=function(){ return false; } } </script>