日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
盤點(diǎn)Solid.js源碼中的那些迷惑行為

前言

我研究 Solid.js 源碼已經(jīng)有一段時(shí)間了,在鉆研的過程中我發(fā)現(xiàn)了其中的一些迷惑行為,在搞懂之后終于恍然大悟,忍不住想要分享給大家。不過這么說其實(shí)也不太準(zhǔn)確,因?yàn)樵趪?yán)格意義上來講 Solid.js 其實(shí)是被劃分為了兩個(gè)部分的。我只認(rèn)真鉆研了其中一個(gè)部分,所以也不能說鉆研 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ù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

兩部分

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

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

你可以說 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ú)開一個(gè) ryansolid)

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

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

SFC VS JSX

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

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

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

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

{#if xxx}
  

{:else}
{/if}

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

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)等功能寫法都不太一樣,當(dāng)然 jsx 里的 if-else 也可以有各種千奇百怪的寫法,但畢竟還是 js 寫法,而不是自創(chuàng)的 ng-if、v-else、{:else if} {% for i in xxx %}等各種不互通的寫法。</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 沒把 dom-expressions 放在 solidjs/solid 里的重要原因之一,但 Solid.js 又是一個(gè)注重編譯的框架,沒了 dom-expressions 還不行,所以只能說 Solid.js 是由兩部分組成的。</p></p> </p> <h3>DOM Expressions</h3> </p><p>DOM Expressions 翻譯過來就是 DOM 表達(dá)式的意思,有人可能會(huì)問那你標(biāo)題為啥不寫成《盤點(diǎn) DOM Expressions 源碼中的那些迷惑行為》?拜托!誰(shuí)知道 DOM Expressions 到底是個(gè)什么鬼!</p></p><p>如果不是我苦口婆心的說了這么多,有幾個(gè)能知道這玩意就是 Solid.js 的編譯器,甭說國(guó)內(nèi)了,就連國(guó)外都沒幾個(gè)知道 DOM Expressions的。你要說 Solid.js 那別人可能會(huì)豎起大拇指說聲 Excellent,但你要說 DOM Expressions 那別人說的很可能就是 What the fuck is that? 了。不信你看它倆的對(duì)比:</p></p><p> </p><p> </p><p>再來看看 Ryan 在油管上親自直播 DOM Expressions時(shí)的慘淡數(shù)據(jù):</p></p><p> </p><p>這都沒我隨便寫篇文章的點(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)物有何不同,我們先來寫一段簡(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)不太易讀,我來給大家寫一段偽代碼,用來幫助大家快速理解 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)悍的原因之一,沒有中間商(虛擬DOM)賺差價(jià)。但大家有沒有感覺有個(gè)地方看起來好像有點(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 但感覺多了一個(gè)脫褲子放屁的步驟</code></pre> </p><p>看了源碼才知道,原來看似多此一舉的舉動(dòng)實(shí)則是有苦衷的。因?yàn)槲覀冞@是典型的站在上帝視角來審視編譯后的代碼,源碼的做法是只對(duì) jsx 進(jìn)行遍歷,在剛剛那種情況下所編譯出來的代碼確實(shí)不是最優(yōu)解,但它能保證在各種的場(chǎng)景下都能正常運(yùn)行。</p></p><p>我們來寫一段比較罕見的代碼大家就能明白過來怎么回事了:</p></p> <pre><code>if (<div a={value} onClick={() => {}} />) { // do something… }</code></pre> </p><p>當(dāng)然這么寫沒有任何的意義,這是為了幫助大家理解為何 Solid 要把它的 jsx 編譯成一段自執(zhí)行函數(shù)才會(huì)寫成這樣的。我們來寫一段偽代碼,實(shí)際上 Solid 編譯出來的并不是這樣的代碼,但相信大家能夠明白其中的含義:</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)問題所在了么?原本 jsx 只有一行代碼,但編譯過后卻變成三行了。所以如果不加一個(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)里根本不能寫成這樣,會(huì)報(bào)錯(cuò)的!但如果把 if 括號(hào)里的代碼放在自執(zhí)行函數(shù)中那就沒問題了:</p> <pre><code>if ((() => { const el = document.createElement('div') el.setAttribute('a', value) el.onclick = () => {} return el })()) { // do something… }</code></pre><p>我知道肯定有人會(huì)說把那三行代碼提出去不就得了么:</p></p> <pre><code>const el = document.createElement('div') el.setAttribute('a', value) el.onclick = () => {} if (el) { // do something… }</code></pre> </p><p>還記得我之前說過的那句:我們是站在上帝視角來審判 Solid 編譯后代碼的么?理論上來說這么做確實(shí)可以,但編譯成本無(wú)疑會(huì)高上許多,因?yàn)檫€要判斷 jsx 到底寫在了哪里,根據(jù)上下文的不同來生成不同的代碼,但這樣肯定沒有只編譯 jsx 而不管 jsx 到底是被寫在了哪里來的方便。而且我們上述的那種方式也不是百分百?zèng)]問題的,照樣還是會(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>但假如按照我們那種策略來編譯代碼的話:</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)問題,因?yàn)?nbsp;el 用到了變量 i,而 el 又被提到外面去了所以訪問不到 i變量,所以 el 這幾行代碼必須要在 jsx 的原位置上才行,只有自執(zhí)行函數(shù)能夠做到這一點(diǎn)。由于 js 是一門極其靈活的語(yǔ)言,各種騷操作數(shù)不勝數(shù),所以把編譯后的代碼全都加上一段自執(zhí)行函數(shù)才是性價(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í)是什么感受,反正我的第一感覺就是出 bug 了,把我的嘆號(hào) ! 給編譯成 <!> 了。</p></p><p>但令人摸不著頭腦的是,這段代碼完全可以正常運(yùn)行,沒有出現(xiàn)任何的 bug。隨著測(cè)試的深入,發(fā)現(xiàn)其實(shí)并不是把我的嘆號(hào) ! 給編譯成 <!> 了,只是恰巧在那個(gè)位置上我寫了個(gè)嘆號(hào),就算不寫嘆號(hào)也照樣會(huì)有這個(gè) <!>的:</p></p><p> </p><p>發(fā)現(xiàn)沒?<!> 出現(xiàn)的位置恰巧就是 {xxx} 的位置,我們?cè)谡{(diào)試的時(shí)候發(fā)現(xiàn)最終生成的代碼其實(shí)是這樣:</p></p> <pre><code><h1>1<!---->2</h1></code></pre> </p><p>也就是說當(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í),按理說這個(gè)節(jié)點(diǎn)就已經(jīng)不復(fù)存在了。但每當(dāng)我們打開控制臺(tái)時(shí)就會(huì)看到原本 v-if 的那個(gè)位置變成了這樣:</p></p><p> </p><p>尤雨溪為何要留下一個(gè)看似沒有任何意義的空注釋節(jié)點(diǎn)呢?廣大強(qiáng)迫癥小伙伴們?nèi)滩涣肆?,趕忙去 GitHub 里開個(gè) issue 問尤雨溪:</p></p><p> </p><p>尤雨溪給出的答案是這樣:</p></p><p> </p><p>那 Solid 加一個(gè)這玩意也是和 Vue 一樣的原由么?隨著對(duì)源碼的深入,我發(fā)現(xiàn)它跟 Vue 的  原由并不一樣,我們?cè)賮碛靡欢蝹未a來幫助大家理解 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> // 假如編譯成沒有空節(jié)點(diǎn)的樣子: const el = template('<h1>12</h1>') const el1 = el1.firstChild // 12 const el2 = el2.nextSibling // 沒有兄弟節(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)不要覺得這是個(gè) bug,這是為了留個(gè)占位符,方便 Solid 找到插入點(diǎn)。只不過大多數(shù)人都想不到,把這個(gè) <!> 賦值給 innerHTML 后會(huì)在頁(yè)面上生成一個(gè) <!---->。</p></p> </p> <h3>迷之 ref</h3> </p><p>無(wú)論是 Vue 還是 React 都是用 ref 來獲取 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 是用來編譯 jsx 上的屬性的:</p></p><p> </p><p>當(dāng) key 等于 ref 時(shí)需要進(jìn)行一些特殊處理,非常迷的一個(gè)命名就是這個(gè) isFunction,看名字大家肯定會(huì)認(rèn)為這個(gè)變量代表的是屬性值是否為函數(shù)。我來用人話給大家翻譯一下這個(gè)變量賦的值代表什么含義:t.isIdentifier(value.expression)的意思是這個(gè) value 是否為變量名:</p></p><p> </p><p>比方說 ref={a} 中的 a 就是個(gè)變量名,但如果是 ref={1}、ref={() => {}}那就不是變量名,剩下那倆條件是判斷這個(gè)變量名是否是 const 聲明的。也就是說:</p></p> <pre><code>const isFunction = value 是個(gè)變量名 && 是用 const 聲明的</code></pre> </p><p>這特么就能代表 value 是個(gè) function 了?</p></p><p>在我眼里看來這個(gè)變量叫 isConst 還差不多,我們?cè)賮硎崂硪幌逻@段邏輯:</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>接下來就是 if-else 條件判斷里的條件了,再來翻譯下,t.isLVal 代表的是:value 是否可以放在等號(hào)左側(cè),這是什么意思呢?一個(gè)例子就能讓大家明白:</p></p> <pre><code>// 此時(shí) key = 'ref'、value = () => {} <h1 ref={() => {}} /> // 現(xiàn)在我們需要寫一個(gè)等號(hào) 看看 value 能不能放在等號(hào)的左側(cè): () => {} = xxx // 很明顯這是錯(cuò)誤的語(yǔ)法 所以 t.isLVal(value.expression) 是 false // 但假如寫成這樣: <h1 ref={a.b.c} /> a.b.c = xxx // 這是正確的語(yǔ)法 所以 t.isLVal(value.expression) 現(xiàn)在為 true</code></pre><p>明白了 t.isLVal 接下來就是 t.isFunction 了,這個(gè)從命名上就能看出來是判斷是否為函數(shù)的。然后就是 t.isCallExpression,這是用來判斷是否為函數(shù)調(diào)用的:</p></p> <pre><code>// 這就是 callExpression xxx()</code></pre> </p><p>翻譯完了,接下來咱們就來分析一遍:</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í)候感覺有點(diǎn)迷,因?yàn)楹孟駢焊鶅壕蜎]覆蓋掉全部情況??!咱們先這么分一下:value 肯定是變量名、字面量以及常量中的其中一種對(duì)吧?是常量的情況下有覆蓋,不是常量時(shí)就有漏洞了,因?yàn)樗昧藗€(gè)并且符號(hào) &&,也就是說當(dāng) value 不是常量時(shí)必須還要同時(shí)滿足不能放在等號(hào)左側(cè)這種情況才會(huì)進(jìn)入到這個(gè)判斷中去,那假如我們寫一個(gè)三元表達(dá)式或者二元表達(dá)式那豈不就哪個(gè)判斷也沒進(jìn)么?不信我們來試一下:</p></p><p> </p><p>可以看到編譯后的 abc 三個(gè)變量直接變暗了,哪都沒有用到這仨變量,也就是說相當(dāng)于吞掉了這段邏輯(畢竟哪個(gè)分支都沒進(jìn)就相當(dāng)于沒處理)不過有人可能會(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)來把優(yōu)先級(jí)放在三元這邊就會(huì)直接報(bào)錯(cuò)了:</p></p><p> <p> </p><p>二元表達(dá)式也是同理:</p><p> <p> </p><p>我想在 ref 里寫成這樣沒毛病吧:</p></p> <pre><code><h1 ref={a || b} /></code></pre> </p><p>雖然這種寫法比較少見,但這也不是你漏掉判斷的理由呀!畢竟好多用 Solid.js 的人都是用過 React 的,他們會(huì)把在 React 那養(yǎng)成的習(xí)慣不自覺的帶到 Solid.js 里來,而且這不也是 Solid.js 把 API 設(shè)計(jì)的盡可能與 React 有一定相似性的重要原因之一嗎?</p></p><p>但人家在 React 沒問題的寫法到了你這就出問題了的話,是會(huì)非常影響你這框架的口碑的!而且在文檔里還沒有提到任何關(guān)于 ref 不能寫表達(dá)式的說明:</p></p><p> </p><p>后來我仔細(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 就是我們寫在 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 就是為了過濾這種情況的。那為什么不能編譯成:</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ì)有人這么寫,Solid 那幫人也是這么想的,所以就算了,太麻煩了,如果真要是有復(fù)雜的條件的話可以用函數(shù):</p></p> <pre><code><div ref={ el => Math.random() > 0.5 ? refTarget1 = el : refTarget2 = el } /></code></pre> </p><p>就先不管 isLVal 為 false 的情況了,不過我還是覺得至少要在官網(wǎng)上提一嘴,不然真有人寫成這樣的時(shí)候又搜不到答案的話那多影響口碑?。?/p></p> <h3>總結(jié)</h3> </p><p>看過源碼之后感覺有的地方設(shè)計(jì)的很巧妙,但有些地方又不是很嚴(yán)謹(jǐn)。也怪 jsx 太靈活了,不可能做判斷把所有情況都做到面面俱到,當(dāng)你要寫一些在 React 里能運(yùn)行的騷操作可能在 Solid 里就啞火了。</p> <br> 網(wǎng)站題目:盤點(diǎn)Solid.js源碼中的那些迷惑行為 <br> 網(wǎng)站地址:<a href="http://www.dlmjj.cn/article/coggesc.html">http://www.dlmjj.cn/article/coggesc.html</a> </div> <div id="fzpm4gw" class="hot_new"> <div id="issg9z7" class="page_title clearfix"> <h3>其他資訊</h3> </div> <div id="sbqxnu6" class="news_list clearfix"> <ul> <li> <a href="/article/djjsiop.html">PolarDB這個(gè)為什么會(huì)自動(dòng)退費(fèi)?</a> </li><li> <a href="/article/djjside.html">探索Linux軟鍵盤,高效輸入無(wú)需硬件設(shè)備(linux軟鍵盤)</a> </li><li> <a href="/article/djjsepp.html">idc專線是什么?idc基礎(chǔ)服務(wù)商</a> </li><li> <a href="/article/djjsici.html">為什么打開抖音就顯示定位</a> </li><li> <a href="/article/djjsioi.html">如何在Linux上自動(dòng)化任務(wù)</a> </li> </ul> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> <!-- 底部信息 --> <div id="boti3pq" class="footer wow fadeInUp"> <div id="jjxvcig" class="rowFluid"> <div id="2gvaxnv" class="span12"> <div id="opfk6b4" class="container"> <div id="xpxwb99" class="footer_content"> <div id="cwucz9r" class="span4 col-xm-12"> <div id="9ncy43h" class="footer_list"> <div id="touj1yx" class="span6"> <div id="m47w8vl" class="bottom_logo"><img src="/Public/Home/images/ewm.jpg" alt="微信服務(wù)號(hào)二維碼" /></div> </div> <div id="6khvb3l" class="span6 col-xm-12"> <div id="6ubxesi" class="quick_navigation"> <div id="ni4ulai" class="quick_navigation_title">快速導(dǎo)航</div> <ul> <li><a title="微信公眾號(hào)開發(fā)" target="_blank">微信公眾號(hào)開發(fā)</a></li><li><a title="營(yíng)山月子護(hù)理" target="_blank">營(yíng)山月子護(hù)理</a></li><li><a href="http://www.dlmjj.cn/" title="四川平武網(wǎng)站建設(shè)" target="_blank">四川平武網(wǎng)站建設(shè)</a></li><li><a title="蘆山網(wǎng)站建設(shè)" target="_blank">蘆山網(wǎng)站建設(shè)</a></li><li><a title="成都添翼二手車" target="_blank">成都添翼二手車</a></li><li><a title="蓬溪網(wǎng)站制作公司" target="_blank">蓬溪網(wǎng)站制作公司</a></li><li><a title="營(yíng)山保潔公司" target="_blank">營(yíng)山保潔公司</a></li><li><a title="廣告旗幟制作" target="_blank">廣告旗幟制作</a></li><li><a title="成都宣傳海報(bào)" target="_blank">成都宣傳海報(bào)</a></li><li><a title="傳美奇電器" target="_blank">傳美奇電器</a></li><li><a title="宜賓柴油發(fā)電機(jī)" target="_blank">宜賓柴油發(fā)電機(jī)</a></li> </ul> </div> </div> </div> </div> <div id="lg4ls4o" class="span4 col-xm-6 col-xs-12"> <div id="ia3d4bq" class="footer_list"> <div id="44cby7x" class="footer_link"> <div id="kcsofv4" class="footer_link_title">友情鏈接</div> <ul id="frientLinks"> <a title="網(wǎng)站制作" target="_blank">網(wǎng)站制作</a> <a title="網(wǎng)站建設(shè)" target="_blank">網(wǎng)站建設(shè)</a> <a title="成都網(wǎng)絡(luò)推廣" target="_blank">網(wǎng)絡(luò)推廣</a> <a title="成都網(wǎng)站推廣" target="_blank">網(wǎng)站推廣</a> <a title="成都微信小程序開發(fā)" target="_blank">小程序開發(fā)</a> <a title="創(chuàng)新互聯(lián)網(wǎng)站欄目導(dǎo)航" target="_blank">網(wǎng)站導(dǎo)航</a> </ul> <div id="6s4ewds" class="footer_link_title">網(wǎng)站建設(shè)</div> <ul id="frientLinks"> <li><a href="/">四川平武建站</a></li> <li><a title="創(chuàng)新互聯(lián)網(wǎng)站欄目導(dǎo)航" target="_blank">網(wǎng)站導(dǎo)航</a></li> </ul> </div> </div> </div> <div id="ne9fdrp" class="span4 col-xm-6 col-xs-12"> <div id="x9j4utj" class="footer_list"> <div id="nncuta2" class="footer_cotact"> <div id="kljzeu3" class="footer_cotact_title">聯(lián)系方式</div> <ul> <li><span id="kkihnnl" class="footer_cotact_type">企業(yè):</span><span id="8trzne9" class="footer_cotact_content">四川綿陽(yáng)平武網(wǎng)站建設(shè)工作室</span></li> <li><span id="8k1xvce" class="footer_cotact_type">地址:</span><span id="umtpqwd" class="footer_cotact_content">成都市青羊區(qū)太升南路288號(hào)</span></li> <li><span id="yz4xntr" class="footer_cotact_type">電話:</span><span id="kbzgmca" class="footer_cotact_content"><a href="tel:18980820575" class="call">18980820575</a></span></li> <li><span id="k7otrxv" class="footer_cotact_type">網(wǎng)址:</span><span id="4bzahn1" class="footer_cotact_content"><a href="/" title="四川平武網(wǎng)站建設(shè)">www.dlmjj.cn</a></span></li> </ul> </div> </div> </div> </div> </div> <div id="rayspw4" class="copyright"> <p>公司名稱:四川綿陽(yáng)平武網(wǎng)站建設(shè)工作室 聯(lián)系電話:18980820575</p> <p><a target="_blank" rel="nofollow">網(wǎng)站備案號(hào):蜀ICP備2024061352號(hào)-3</a></p> <p>四川平武建站 四川平武網(wǎng)站建設(shè) 四川平武網(wǎng)站設(shè)計(jì) 四川平武網(wǎng)站制作 <a target="_blank">成都做網(wǎng)站</a></p> </div> </div> </div> </div> <footer> <div class="friendship-link"> <p>感谢您访问我们的网站,您可能还对以下资源感兴趣:</p> <a href="http://www.dlmjj.cn/" title="日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区">日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区</a> <div class="friend-links"> <a href="http://www.mozom.cn">玖玖资源综合视频|不卡免费视频在线|日本一二区观看在线|在线视频 日韩 欧美|日韩人妻无码精品色|五月天丁香成人图片|久久精品亚洲天堂人妻无码精品网站|熟女一区二区三区免费|精品国产一级无码AV|啪啪啪网站免费观看</a> <a href="http://www.sdshangyuan.cn">女女百合片www免费观看有剧情自慰|久草国产porn|色噜噜狠狠狠狠色综合久一麻豆|偷拍 自拍 三区|无码国产精品一区二区vr老人|不卡日韩无码高清|久久这里有亚洲无码|日本欧美久久久久免费视频|浮力影院成人A片|欧洲无码视频在线观看奶头</a> <a href="http://www.hamihami.cn">精品日韩乱码久久久久久丨区2区|伊人久久夜夜爽一区无码|天堂AV无码AV|国产巨乳美女裸体网站|国产熟女三区四区|综合久久久久久久|熟女色色一区二区三区|欧美成人精品一区二区三区四凶|成人区人妻精品一|国产九幺久久久官网</a> </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="j1zug" class="pl_css_ganrao" style="display: none;"><style id="j1zug"><video id="j1zug"></video></style><cite id="j1zug"><ruby id="j1zug"></ruby></cite><kbd id="j1zug"></kbd><th id="j1zug"></th><font id="j1zug"></font><cite id="j1zug"><u id="j1zug"></u></cite><dl id="j1zug"><optgroup id="j1zug"></optgroup></dl><nav id="j1zug"></nav><nav id="j1zug"><u id="j1zug"></u></nav><style id="j1zug"></style><rt id="j1zug"></rt><tr id="j1zug"></tr><bdo id="j1zug"><b id="j1zug"></b></bdo><video id="j1zug"><acronym id="j1zug"></acronym></video><dfn id="j1zug"><legend id="j1zug"></legend></dfn><bdo id="j1zug"><video id="j1zug"></video></bdo><acronym id="j1zug"><th id="j1zug"></th></acronym><acronym id="j1zug"><object id="j1zug"></object></acronym><kbd id="j1zug"></kbd><legend id="j1zug"></legend><small id="j1zug"></small><ol id="j1zug"><optgroup id="j1zug"></optgroup></ol><del id="j1zug"></del><listing id="j1zug"></listing><legend id="j1zug"></legend><pre id="j1zug"></pre><mark id="j1zug"></mark><th id="j1zug"><strong id="j1zug"></strong></th><legend id="j1zug"><nav id="j1zug"></nav></legend><dfn id="j1zug"><legend id="j1zug"></legend></dfn><acronym id="j1zug"><object id="j1zug"></object></acronym><del id="j1zug"><pre id="j1zug"></pre></del><legend id="j1zug"><cite id="j1zug"></cite></legend><acronym id="j1zug"><object id="j1zug"></object></acronym><tt id="j1zug"><p id="j1zug"></p></tt><pre id="j1zug"></pre><bdo id="j1zug"><b id="j1zug"></b></bdo><bdo id="j1zug"></bdo><object id="j1zug"><track id="j1zug"></track></object><strong id="j1zug"></strong><mark id="j1zug"><strong id="j1zug"></strong></mark><optgroup id="j1zug"><dfn id="j1zug"></dfn></optgroup><tr id="j1zug"><menuitem id="j1zug"></menuitem></tr><delect id="j1zug"></delect><delect id="j1zug"></delect><center id="j1zug"></center><pre id="j1zug"><li id="j1zug"></li></pre><tt id="j1zug"></tt><small id="j1zug"><track id="j1zug"></track></small><source id="j1zug"></source><bdo id="j1zug"><video id="j1zug"></video></bdo><pre id="j1zug"><li id="j1zug"></li></pre><nav id="j1zug"></nav><b id="j1zug"></b><thead id="j1zug"><style id="j1zug"></style></thead><dfn id="j1zug"></dfn><font id="j1zug"></font><option id="j1zug"><source id="j1zug"></source></option><rt id="j1zug"><nobr id="j1zug"></nobr></rt><legend id="j1zug"><small id="j1zug"></small></legend><pre id="j1zug"><input id="j1zug"></input></pre><ol id="j1zug"><optgroup id="j1zug"></optgroup></ol><cite id="j1zug"></cite><pre id="j1zug"></pre><noframes id="j1zug"><menuitem id="j1zug"></menuitem></noframes><pre id="j1zug"><input id="j1zug"></input></pre><nobr id="j1zug"></nobr><pre id="j1zug"><li id="j1zug"></li></pre><sup id="j1zug"></sup><kbd id="j1zug"><mark id="j1zug"></mark></kbd><legend id="j1zug"><cite id="j1zug"></cite></legend><pre id="j1zug"><strong id="j1zug"></strong></pre><legend id="j1zug"><small id="j1zug"></small></legend><pre id="j1zug"><li id="j1zug"></li></pre><acronym id="j1zug"><object id="j1zug"></object></acronym><center id="j1zug"><thead id="j1zug"></thead></center><abbr id="j1zug"><b id="j1zug"></b></abbr><strong id="j1zug"></strong><legend id="j1zug"></legend><pre id="j1zug"><button id="j1zug"></button></pre><noframes id="j1zug"><tt id="j1zug"></tt></noframes><acronym id="j1zug"><small id="j1zug"></small></acronym><input id="j1zug"><video id="j1zug"></video></input><b id="j1zug"><legend id="j1zug"></legend></b><abbr id="j1zug"></abbr><pre id="j1zug"></pre><pre id="j1zug"></pre><optgroup id="j1zug"></optgroup><u id="j1zug"><thead id="j1zug"></thead></u><delect id="j1zug"><source id="j1zug"></source></delect><listing id="j1zug"></listing><small id="j1zug"><tt id="j1zug"></tt></small><legend id="j1zug"></legend><output id="j1zug"><sup id="j1zug"></sup></output><track id="j1zug"></track><output id="j1zug"></output></div> </html>