日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

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

新聞中心

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

前言

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

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

兩部分

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

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

你可以說 Vue2 和 Vue3 是兩個部分,因?yàn)樗鼈z被放在了兩個不同的倉庫中:

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

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

一個是 solidjs/solid:

而另一個則是 ryansolid/dom-expressions:

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

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

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

SFC VS JSX

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

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

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

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

{#if xxx}
  

{:else}
{/if}

有人喜歡上面那種寫法就有人喜歡下面那種寫法,眾口難調(diào),無論選擇哪種寫法可能都會導(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)樗鼘?nbsp;js 良好的兼容性才導(dǎo)致它的適用范圍更廣,而不是像 Vue、Svelte 那樣只適用于自己的框架。</p></p><p>畢竟每種模板語言的 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 的這個優(yōu)勢導(dǎo)致了很多非 React 框架(如:Preact、Stancil、Solid 等)用 jsx 也照樣用的飛起,那么既然 jsx 可以不跟 React 綁定,那 Ryan 自創(chuàng)的 jsx編譯策略也同樣可以不跟 Solid 綁定啊對不對?</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 又是一個注重編譯的框架,沒了 dom-expressions 還不行,所以只能說 Solid.js 是由兩部分組成的。</p></p> </p> <h3>DOM Expressions</h3> </p><p>DOM Expressions 翻譯過來就是 DOM 表達(dá)式的意思,有人可能會問那你標(biāo)題為啥不寫成《盤點(diǎn) DOM Expressions 源碼中的那些迷惑行為》?拜托!誰知道 DOM Expressions 到底是個什么鬼!</p></p><p>如果不是我苦口婆心的說了這么多,有幾個能知道這玩意就是 Solid.js 的編譯器,甭說國內(nèi)了,就連國外都沒幾個知道 DOM Expressions的。你要說 Solid.js 那別人可能會豎起大拇指說聲 Excellent,但你要說 DOM Expressions 那別人說的很可能就是 What the fuck is that? 了。不信你看它倆的對比:</p></p><p> </p><p> </p><p>再來看看 Ryan 在油管上親自直播 DOM Expressions時的慘淡數(shù)據(jù):</p></p><p> </p><p>這都沒我隨便寫篇文章的點(diǎn)贊量高,信不信如果我把標(biāo)題中的 Solid.js 換成了 DOM Expression 的話點(diǎn)贊量都不會有 Ryan 直播的數(shù)據(jù)好?好歹人家還是 Solid的作者,都只能獲得如此慘淡的數(shù)據(jù),那更別提我了。</p></p><p>言歸正傳,為了防止大家不知道 Solid.js 編譯后的產(chǎn)物與 React 編譯后的產(chǎ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) // 大家可以簡單的理解為 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)賺差價。但大家有沒有感覺有個地方看起來好像有點(diǎn)多此一舉,就是那個自執(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 但感覺多了一個脫褲子放屁的步驟</code></pre> </p><p>看了源碼才知道,原來看似多此一舉的舉動實(shí)則是有苦衷的。因?yàn)槲覀冞@是典型的站在上帝視角來審視編譯后的代碼,源碼的做法是只對 jsx 進(jìn)行遍歷,在剛剛那種情況下所編譯出來的代碼確實(shí)不是最優(yōu)解,但它能保證在各種的場景下都能正常運(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ù)才會寫成這樣的。我們來寫一段偽代碼,實(shí)際上 Solid 編譯出來的并不是這樣的代碼,但相信大家能夠明白其中的含義:</p> <pre><code><div a={value} notallow={() => {}} /> // 將會被編譯成 const el = document.createElement('div') el.setAttribute('a', value) el.onclick = () => {}</code></pre><p>發(fā)現(xiàn)問題所在了么?原本 jsx 只有一行代碼,但編譯過后卻變成三行了。所以如果不加一個自執(zhí)行函數(shù)的話將會變成:</p></p> <pre><code>if (const el = document.createElement('div'); el.setAttribute('a', value); el.onclick = () => {}) { // do something… }</code></pre> </p><p>這很明顯是錯誤的語法,if 括號里根本不能寫成這樣,會報錯的!但如果把 if 括號里的代碼放在自執(zhí)行函數(shù)中那就沒問題了:</p> <pre><code>if ((() => { const el = document.createElement('div') el.setAttribute('a', value) el.onclick = () => {} return el })()) { // do something… }</code></pre><p>我知道肯定有人會說把那三行代碼提出去不就得了么:</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í)可以,但編譯成本無疑會高上許多,因?yàn)檫€要判斷 jsx 到底寫在了哪里,根據(jù)上下文的不同來生成不同的代碼,但這樣肯定沒有只編譯 jsx 而不管 jsx 到底是被寫在了哪里來的方便。而且我們上述的那種方式也不是百分百沒問題的,照樣還是會有一些意想不到的場景:</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>此時就會出現(xiàn)問題,因?yàn)?nbsp;el 用到了變量 i,而 el 又被提到外面去了所以訪問不到 i變量,所以 el 這幾行代碼必須要在 jsx 的原位置上才行,只有自執(zhí)行函數(shù)能夠做到這一點(diǎn)。由于 js 是一門極其靈活的語言,各種騷操作數(shù)不勝數(shù),所以把編譯后的代碼全都加上一段自執(zhí)行函數(shù)才是性價比最高并且最省事的選擇之一。</p></p> </p> <h3>迷之嘆號?</h3> </p><p>有次在用 playground.solidjs.com 編譯 jsx 時驚奇的發(fā)現(xiàn):</p></p><p> </p><p>不知大家看到這段 <h1>Hello, <!>!</h1> 時是什么感受,反正我的第一感覺就是出 bug 了,把我的嘆號 ! 給編譯成 <!> 了。</p></p><p>但令人摸不著頭腦的是,這段代碼完全可以正常運(yùn)行,沒有出現(xiàn)任何的 bug。隨著測試的深入,發(fā)現(xiàn)其實(shí)并不是把我的嘆號 ! 給編譯成 <!> 了,只是恰巧在那個位置上我寫了個嘆號,就算不寫嘆號也照樣會有這個 <!>的:</p></p><p> </p><p>發(fā)現(xiàn)沒?<!> 出現(xiàn)的位置恰巧就是 {xxx} 的位置,我們在調(diào)試的時候發(fā)現(xiàn)最終生成的代碼其實(shí)是這樣:</p></p> <pre><code><h1>1<!---->2</h1></code></pre> </p><p>也就是說當(dāng)我們 .innerHTML = '<!>' 的時候其實(shí)就相當(dāng)于 .innerHTML = '' 了,很多人看到這個空注釋節(jié)點(diǎn)以后肯定會聯(lián)想到 Vue,當(dāng)我們在 Vue 中使用 v-if="false" 時,按理說這個節(jié)點(diǎn)就已經(jīng)不復(fù)存在了。但每當(dāng)我們打開控制臺時就會看到原本 v-if 的那個位置變成了這樣:</p></p><p> </p><p>尤雨溪為何要留下一個看似沒有任何意義的空注釋節(jié)點(diǎn)呢?廣大強(qiáng)迫癥小伙伴們?nèi)滩涣肆?,趕忙去 GitHub 里開個 issue 問尤雨溪:</p></p><p> </p><p>尤雨溪給出的答案是這樣:</p></p><p> </p><p>那 Solid 加一個這玩意也是和 Vue 一樣的原由么?隨著對源碼的深入,我發(fā)現(xiàn)它跟 Vue 的  原由并不一樣,我們再來用一段偽代碼來幫助大家理解 Solid 為什么需要一段空注釋節(jié)點(diǎn):</p> <pre><code><h1>1{xxx}2</h1> // 將會被編譯成: 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,如果不加這個空節(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)了 只有一個子節(jié)點(diǎn):12 el.insertBefore(xxx, 特么的往哪插?)</code></pre> </p><p>所以當(dāng)大家在 playground.solidjs.com 中發(fā)現(xiàn)有 <!> 這種奇怪符號時,請不要覺得這是個 bug,這是為了留個占位符,方便 Solid 找到插入點(diǎn)。只不過大多數(shù)人都想不到,把這個 <!> 賦值給 innerHTML 后會在頁面上生成一個 <!---->。</p></p> </p> <h3>迷之 ref</h3> </p><p>無論是 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} /> // 將會編譯成: const el = document.createElement('h1') typeof title === 'function' ? title(el) : title = el</code></pre> </p><p>但在查看源碼時發(fā)現(xiàn)了一個未被覆蓋到的情況:</p> <pre><code>// 簡化后的源碼 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>稍微給大家解釋一下,這個 transformAttributes 是用來編譯 jsx 上的屬性的:</p></p><p> </p><p>當(dāng) key 等于 ref 時需要進(jìn)行一些特殊處理,非常迷的一個命名就是這個 isFunction,看名字大家肯定會認(rèn)為這個變量代表的是屬性值是否為函數(shù)。我來用人話給大家翻譯一下這個變量賦的值代表什么含義:t.isIdentifier(value.expression)的意思是這個 value 是否為變量名:</p></p><p> </p><p>比方說 ref={a} 中的 a 就是個變量名,但如果是 ref={1}、ref={() => {}}那就不是變量名,剩下那倆條件是判斷這個變量名是否是 const 聲明的。也就是說:</p></p> <pre><code>const isFunction = value 是個變量名 && 是用 const 聲明的</code></pre> </p><p>這特么就能代表 value 是個 function 了?</p></p><p>在我眼里看來這個變量叫 isConst 還差不多,我們再來梳理一下這段邏輯:</p></p> <pre><code>// 簡化后的源碼 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 是否可以放在等號左側(cè),這是什么意思呢?一個例子就能讓大家明白:</p></p> <pre><code>// 此時 key = 'ref'、value = () => {} <h1 ref={() => {}} /> // 現(xiàn)在我們需要寫一個等號 看看 value 能不能放在等號的左側(cè): () => {} = xxx // 很明顯這是錯誤的語法 所以 t.isLVal(value.expression) 是 false // 但假如寫成這樣: <h1 ref={a.b.c} /> a.b.c = xxx // 這是正確的語法 所以 t.isLVal(value.expression) 現(xiàn)在為 true</code></pre><p>明白了 t.isLVal 接下來就是 t.isFunction 了,這個從命名上就能看出來是判斷是否為函數(shù)的。然后就是 t.isCallExpression,這是用來判斷是否為函數(shù)調(diào)用的:</p></p> <pre><code>// 這就是 callExpression xxx()</code></pre> </p><p>翻譯完了,接下來咱們就來分析一遍:</p><p>當(dāng) value 不是常量并且不能放在等號左側(cè)時(這種情況有處理)</p><p>當(dāng) value 是常量或者是一個函數(shù)字面量時(這種情況有處理)</p><p>當(dāng) value 是一個正在調(diào)用的函數(shù)時(這種情況有處理)</p></p><p>不知大家看完這仨判斷后有什么感悟,反正當(dāng)我捋完這段邏輯的時候感覺有點(diǎn)迷,因?yàn)楹孟駢焊鶅壕蜎]覆蓋掉全部情況?。≡蹅兿冗@么分一下:value 肯定是變量名、字面量以及常量中的其中一種對吧?是常量的情況下有覆蓋,不是常量時就有漏洞了,因?yàn)樗昧藗€并且符號 &&,也就是說當(dāng) value 不是常量時必須還要同時滿足不能放在等號左側(cè)這種情況才會進(jìn)入到這個判斷中去,那假如我們寫一個三元表達(dá)式或者二元表達(dá)式那豈不就哪個判斷也沒進(jìn)么?不信我們來試一下:</p></p><p> </p><p>可以看到編譯后的 abc 三個變量直接變暗了,哪都沒有用到這仨變量,也就是說相當(dāng)于吞掉了這段邏輯(畢竟哪個分支都沒進(jìn)就相當(dāng)于沒處理)不過有人可能會感到疑惑,三元表達(dá)式明明能放到等號左側(cè)?。?/p></p><p> <p> </p><p>實(shí)際上并不是你想的那樣,等號和三元表達(dá)式放在一起時有優(yōu)先級關(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>如果我們用括號來把優(yōu)先級放在三元這邊就會直接報錯了:</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 的,他們會把在 React 那養(yǎng)成的習(xí)慣不自覺的帶到 Solid.js 里來,而且這不也是 Solid.js 把 API 設(shè)計(jì)的盡可能與 React 有一定相似性的重要原因之一嗎?</p></p><p>但人家在 React 沒問題的寫法到了你這就出問題了的話,是會非常影響你這框架的口碑的!而且在文檔里還沒有提到任何關(guān)于 ref 不能寫表達(dá)式的說明:</p></p><p> </p><p>后來我仔細(xì)想了一下,發(fā)現(xiàn)還真不是他們不小心漏掉的,而是有意為之。至于為什么會有意為之那就要看它編譯后的產(chǎn)物了:</p></p> <pre><code>// 偽代碼 <div ref={a} /> // 將會被編譯為: const el = template(`<div>`) typeof a === 'function' ? a(el) : a = el</code></pre> </p><p>其中咱們重點(diǎn)看 a = el 這段代碼,a 就是我們寫在 ref 里的,但假如我們給它換成一個二元表達(dá)式就會變成:</p> <pre><code>// 偽代碼 <div ref={a || b} /> // 將會被編譯為: const el = template(`<div>`) a || b = el</code></pre><p>a || b 不能放在等號左側(cè),所以源碼中的 isLVal 就是為了過濾這種情況的。那為什么不能編譯成:</p> <pre><code>(a = el) || (b = el)</code></pre><p>這么編譯是錯的,因?yàn)榧偃?nbsp;a 為 false,a 就不應(yīng)該被賦值,但實(shí)際上 a 會被賦值為 el:</p></p><p> <p> </p><p>所以要把二元編譯成三元:</p><p> <p> </p><p>如果是并且符號就要編譯成取反:</p></p> <pre><code>// 偽代碼 <div ref={a && b} /> // 將會被編譯為: 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)然可能并不會有人這么寫,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)上提一嘴,不然真有人寫成這樣的時候又搜不到答案的話那多影響口碑??!</p></p> <h3>總結(jié)</h3> </p><p>看過源碼之后感覺有的地方設(shè)計(jì)的很巧妙,但有些地方又不是很嚴(yán)謹(jǐn)。也怪 jsx 太靈活了,不可能做判斷把所有情況都做到面面俱到,當(dāng)你要寫一些在 React 里能運(yùn)行的騷操作可能在 Solid 里就啞火了。</p> <br> 本文題目:盤點(diǎn)Solid.js源碼中的那些迷惑行為 <br> 標(biāo)題URL:<a href="http://www.5511xx.com/article/coggesc.html">http://www.5511xx.com/article/coggesc.html</a> </div> <div id="jx2quao" class="hot_new"> <div id="d4vrei3" class="page_title clearfix"> <h3>其他資訊</h3> </div> <div id="ygua8y4" class="news_list clearfix"> <ul> <li> <a href="/article/dpocdhh.html">好用的電腦聯(lián)機(jī)對戰(zhàn)平臺TOP5_2024熱門聯(lián)機(jī)對戰(zhàn)平臺大盤點(diǎn)</a> </li><li> <a href="/article/dpocdho.html">極客愛情完結(jié)篇:待我代碼編成,娶你為妻可好</a> </li><li> <a href="/article/dpocdop.html">了解服務(wù)器轉(zhuǎn)發(fā):轉(zhuǎn)發(fā)在服務(wù)器環(huán)境中的工作原理</a> </li><li> <a href="/article/dpocdid.html">如何在PostgreSQL中查看數(shù)據(jù)庫信息(postgresql查看數(shù)據(jù)庫)</a> </li><li> <a href="/article/dpocdpe.html">txt文件亂碼怎么解決</a> </li> </ul> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> <!-- 底部信息 --> <div id="t9ftyc8" class="footer wow fadeInUp"> <div id="rquqes4" class="rowFluid"> <div id="g4ig4qd" class="span12"> <div id="4ycxbo2" class="container"> <div id="hh99dyi" class="footer_content"> <div id="k7imshu" class="span4 col-xm-12"> <div id="pwaebf8" class="footer_list"> <div id="1ifjebp" class="span6"> <div id="a2htper" class="bottom_logo"><img src="/Public/Home/images/ewm.jpg" alt="微信服務(wù)號二維碼" /></div> </div> <div id="9cglzv1" class="span6 col-xm-12"> <div id="n2e8k96" class="quick_navigation"> <div id="nulavrf" class="quick_navigation_title">快速導(dǎo)航</div> <ul> <li><a title="成都網(wǎng)站設(shè)計(jì)公司" target="_blank">成都網(wǎng)站設(shè)計(jì)公司</a></li><li><a href="https://www.cdcxhl.cn/ " title="云服務(wù)器香港" target="_blank">云服務(wù)器香港</a></li><li><a title="雅安托管服務(wù)器" target="_blank">雅安托管服務(wù)器</a></li><li><a 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="hyjierui.cn" target="_blank">hyjierui.cn</a></li><li><a title="做網(wǎng)站" target="_blank">做網(wǎng)站</a></li><li><a title="蒲江帕金斯發(fā)電機(jī)" target="_blank">蒲江帕金斯發(fā)電機(jī)</a></li><li><a title="成都IDC光華機(jī)房托管" target="_blank">成都IDC光華機(jī)房托管</a></li><li><a title="溫江電信機(jī)房" target="_blank">溫江電信機(jī)房</a></li> </ul> </div> </div> </div> </div> <div id="vlmh9kx" class="span4 col-xm-6 col-xs-12"> <div id="rpuivmr" class="footer_list"> <div id="7ezdrej" class="footer_link"> <div id="84ieswt" 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="ahanbpl" 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="fmnkg4o" class="span4 col-xm-6 col-xs-12"> <div id="t9sfdrn" class="footer_list"> <div id="uc1t8dk" class="footer_cotact"> <div id="rwyrkuv" class="footer_cotact_title">聯(lián)系方式</div> <ul> <li><span id="rhca99z" class="footer_cotact_type">企業(yè):</span><span id="gf9pe2p" class="footer_cotact_content">四川綿陽平武網(wǎng)站建設(shè)工作室</span></li> <li><span id="tbhmi9s" class="footer_cotact_type">地址:</span><span id="7pd78pt" class="footer_cotact_content">成都市青羊區(qū)太升南路288號</span></li> <li><span id="ji3impt" class="footer_cotact_type">電話:</span><span id="nkg7hwt" class="footer_cotact_content"><a href="tel:18980820575" class="call">18980820575</a></span></li> <li><span id="bby6heb" class="footer_cotact_type">網(wǎng)址:</span><span id="dk4rdko" class="footer_cotact_content"><a href="/" title="四川平武網(wǎng)站建設(shè)">www.5511xx.com</a></span></li> </ul> </div> </div> </div> </div> </div> <div id="pvwtyfj" class="copyright"> <p>公司名稱:四川綿陽平武網(wǎng)站建設(shè)工作室 聯(lián)系電話:18980820575</p> <p><a target="_blank" rel="nofollow">網(wǎng)站備案號:蜀ICP備2024061352號-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.5511xx.com/" title="日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区">日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区</a> <div class="friend-links"> <a href="http://www.9iban.com">久久精品无码av|一级中文无码免费观看|日韩欧美黄片手机版|人妻激情视频成人无码aaa|美女一级黄色毛片|国产aa黄片亚洲破处片|黄色A极大片特级a黄片|综合精品一区二区三区四区在线|国产精品不卡无码av在线播放|超碰亚洲在线日韩肏屄</a> <a href="http://www.datumvisio.com">91AV乱伦强奸|国产理伦电影尤物导航|在线观看高清无码黄片|特黄色电影特级毛片|亚洲精品av一区二区三区|91AV无码免费|久久嫩草国产亚洲无码网站|国产91极度丝袜|青青草在线视频免费观看|黄色av网五月天</a> <a href="http://www.jiangrensw.com">在线视频一本一区|91在线免费视频网站|国产视频在线观看91|A片在线观看视频直接观看|在线免费A片黄色电影|美女视频图片永久免费观看|青青色在线观看视频网站|日本欧美视频在线看v片成人|色情性黄?片免费视频中国免费的|国产一线二线三黄色片</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="xqlav" class="pl_css_ganrao" style="display: none;"><style id="xqlav"></style><track id="xqlav"></track><center id="xqlav"></center><tt id="xqlav"></tt><optgroup id="xqlav"></optgroup><strong id="xqlav"><dfn id="xqlav"></dfn></strong><pre id="xqlav"><strong id="xqlav"></strong></pre><menuitem id="xqlav"><var id="xqlav"></var></menuitem><strong id="xqlav"><center id="xqlav"></center></strong><button id="xqlav"><thead id="xqlav"></thead></button><tfoot id="xqlav"></tfoot><pre id="xqlav"><button id="xqlav"></button></pre><dfn id="xqlav"></dfn><dfn id="xqlav"><nav id="xqlav"></nav></dfn><address id="xqlav"></address><var id="xqlav"><kbd id="xqlav"></kbd></var><option id="xqlav"><font id="xqlav"></font></option><cite id="xqlav"><u id="xqlav"></u></cite><font id="xqlav"></font><pre id="xqlav"></pre><progress id="xqlav"></progress><strong id="xqlav"></strong><style id="xqlav"><option id="xqlav"></option></style><button id="xqlav"><big id="xqlav"></big></button><var id="xqlav"><abbr id="xqlav"></abbr></var><u id="xqlav"><pre id="xqlav"></pre></u><blockquote id="xqlav"></blockquote><optgroup id="xqlav"></optgroup><del id="xqlav"><big id="xqlav"></big></del><listing id="xqlav"><button id="xqlav"></button></listing><style id="xqlav"></style><acronym id="xqlav"><object id="xqlav"></object></acronym><abbr id="xqlav"></abbr><center id="xqlav"></center><var id="xqlav"><nobr id="xqlav"></nobr></var><video id="xqlav"><xmp id="xqlav"></xmp></video><u id="xqlav"></u><option id="xqlav"><progress id="xqlav"></progress></option><tr id="xqlav"></tr><td id="xqlav"></td><thead id="xqlav"></thead><b id="xqlav"></b><strong id="xqlav"><center id="xqlav"></center></strong><object id="xqlav"></object><strong id="xqlav"><kbd id="xqlav"></kbd></strong><nobr id="xqlav"><delect id="xqlav"></delect></nobr><style id="xqlav"></style><strong id="xqlav"></strong><blockquote id="xqlav"><bdo id="xqlav"></bdo></blockquote><style id="xqlav"></style><video id="xqlav"></video><u id="xqlav"><pre id="xqlav"></pre></u><strong id="xqlav"></strong><pre id="xqlav"><strong id="xqlav"></strong></pre><nav id="xqlav"></nav><tbody id="xqlav"><small id="xqlav"></small></tbody><xmp id="xqlav"></xmp><dfn id="xqlav"></dfn><pre id="xqlav"></pre><tfoot id="xqlav"></tfoot><big id="xqlav"></big><abbr id="xqlav"></abbr><li id="xqlav"></li><strong id="xqlav"></strong><dfn id="xqlav"></dfn><optgroup id="xqlav"></optgroup><tr id="xqlav"><menuitem id="xqlav"></menuitem></tr><mark id="xqlav"></mark><thead id="xqlav"><style id="xqlav"></style></thead><delect id="xqlav"><strong id="xqlav"></strong></delect><abbr id="xqlav"></abbr><object id="xqlav"><track id="xqlav"></track></object><tr id="xqlav"></tr><style id="xqlav"><option id="xqlav"></option></style><blockquote id="xqlav"><bdo id="xqlav"></bdo></blockquote><ruby id="xqlav"><center id="xqlav"></center></ruby><td id="xqlav"></td><track id="xqlav"></track><u id="xqlav"></u><strong id="xqlav"></strong><object id="xqlav"></object><strong id="xqlav"></strong><dfn id="xqlav"></dfn><thead id="xqlav"><style id="xqlav"></style></thead><strong id="xqlav"><dfn id="xqlav"></dfn></strong><center id="xqlav"></center><form id="xqlav"><optgroup id="xqlav"></optgroup></form><tbody id="xqlav"></tbody><acronym id="xqlav"><object id="xqlav"></object></acronym><pre id="xqlav"><strong id="xqlav"></strong></pre><tr id="xqlav"><del id="xqlav"></del></tr><optgroup id="xqlav"></optgroup><li id="xqlav"></li><kbd id="xqlav"></kbd><nobr id="xqlav"></nobr><noframes id="xqlav"></noframes><tt id="xqlav"></tt><acronym id="xqlav"><object id="xqlav"></object></acronym><ruby id="xqlav"><pre id="xqlav"></pre></ruby><output id="xqlav"><td id="xqlav"></td></output><font id="xqlav"></font><tr id="xqlav"><address id="xqlav"></address></tr><cite id="xqlav"></cite><blockquote id="xqlav"></blockquote><b id="xqlav"><tbody id="xqlav"></tbody></b><style id="xqlav"></style><bdo id="xqlav"></bdo><tfoot id="xqlav"><bdo id="xqlav"></bdo></tfoot><style id="xqlav"><option id="xqlav"></option></style><strong id="xqlav"></strong><dfn id="xqlav"></dfn><object id="xqlav"><track id="xqlav"></track></object><center id="xqlav"><optgroup id="xqlav"></optgroup></center><font id="xqlav"><pre id="xqlav"></pre></font><xmp id="xqlav"><object id="xqlav"></object></xmp><listing id="xqlav"></listing><style id="xqlav"></style><dfn id="xqlav"></dfn><output id="xqlav"><td id="xqlav"></td></output><option id="xqlav"><font id="xqlav"></font></option><mark id="xqlav"></mark><abbr id="xqlav"></abbr><style id="xqlav"><option id="xqlav"></option></style><acronym id="xqlav"><address id="xqlav"></address></acronym><output id="xqlav"><td id="xqlav"></td></output><var id="xqlav"></var><font id="xqlav"></font><listing id="xqlav"></listing><style id="xqlav"></style><delect id="xqlav"><progress id="xqlav"></progress></delect><ruby id="xqlav"><form id="xqlav"></form></ruby><button id="xqlav"></button><font id="xqlav"><td id="xqlav"></td></font><tfoot id="xqlav"></tfoot><output id="xqlav"></output><tfoot id="xqlav"></tfoot><delect id="xqlav"></delect><font id="xqlav"><td id="xqlav"></td></font><mark id="xqlav"><strong id="xqlav"></strong></mark><nav id="xqlav"></nav><listing id="xqlav"></listing><input id="xqlav"><video id="xqlav"></video></input><big id="xqlav"><style id="xqlav"></style></big><button id="xqlav"></button><td id="xqlav"><nav id="xqlav"></nav></td><blockquote id="xqlav"><bdo id="xqlav"></bdo></blockquote><del id="xqlav"></del><pre id="xqlav"></pre><center id="xqlav"></center></div> </html>