前言

如果你想把東西存在網頁前端,也就是存在瀏覽器裡面,基本上就是以下這幾個選項:

  1. Cookie
  2. LocalStorage
  3. SessionStorage
  4. IndexedDB
  5. Web SQL

後兩者應該滿少用到的,而最後一個 Web SQL 也早在幾年前就被宣告已經不再維護了。因此在談到儲存資料的時候,大部分的人提的還是前三種,其中又以前兩種最多人使用。

畢竟在前端儲存資料時,大部分資料都希望能儲存一段時間,而 cookie 跟 localStorage 就是被設計在這種情形下用的,可是 sessionStorage 不是,它只適合儲存非常短期的資料。

不知道大家對 sessionStorage 的理解是不是跟我一樣,先說說我的理解好了:

sessionStorage 跟 localStorage 最大的差別在於前者只會存在於一個分頁當中,你分頁關掉之後資料就清除了,所以新開分頁,就會有新的 sessionStorage,在不同分頁不會共用。但後者如果是相同的網站,可以共用同一個 localStorage

但我想問大家的是:有沒有可能有一種情況,我在分頁 A 的 sessionStorage 存了一些東西,然後有一個新的分頁 B,也可以讀到分頁 A 的 sessionStorage?

你可能以為沒有,我以前也以為沒有,我同事也這樣認為。

但偏偏就是有。

閱讀更多

前言

不知道大家有沒有聽過 vite 這個工具,看它名字有個 v,大概就可以猜到可能跟 Vue 有關。沒錯,這是 Vue 的作者尤雨溪開發出來的另外一套工具,原本是想要給 VuePress 用的,但是強大之處就在於它不僅限於此。

Vite 在 GitHub 上的 About 只寫了兩個句子:

Native-ESM powered web dev build tool. It’s fast.

如果你有體驗過,就會發現真的很快。Vite 是 build tool 跟 dev server 的綜合體,這篇會簡單教大家使用一下 vite,然後來談 ES modules,再來看看 vite 神奇的地方。

閱讀更多

前言

之前在公司裡面做一些效能上的調整時,無意間發現了一個奇怪的現象,繼續往下追查之後才發現是個好像沒有被什麼人發現過的 bug,而且成因我覺得挺有趣的,就想說可以寫一篇跟大家分享一下。

這篇技術含量不高,可以抱持著看故事的心態來看這篇,會比較有趣一點。

故事的開端

故事的起源呢,是之前在公司裡面要做一些網站上的調整,試著增進一下載入的速度。當我們談到性能最佳化這一塊,其實有很多可以做的,例如說跟 Server 那邊比較有關的是:

  1. 使用 HTTP/2
  2. 使用 gzip 或是 brotli 進行壓縮
  3. 使用 Cache(可以加快 revisit 的速度)
  4. 使用 CDN
  5. 降低 TTFB 時間

不過以上都需要後端或是 SRE 的協助,跟前端其實關係不大。跟前端關係比較大的,也可以分成很多面向來看,例如說以「減少資源」的角度來看,可以做的事情有:

  1. Image 格式調整(壓縮 + webp 或其他格式)
  2. JS 大小(ugligy、code spliting、dynamic import)
  3. CSS 大小(minify、移除不需要的 CSS)

如果以「加速載入重要資源」的角度,可以加上 preload 或是 preconnect 這些 hint,來提示瀏覽器哪些東西應該先被載入。

還可以從「減少 JS 執行時間」的角度來看,例如說如果是寫 React,可以用 shouldComponentUpdate、PureComponent 或是 memo 來減少不必要的 re-render。

這一篇既然標題都寫 styled components 了,主題當然就是圍繞在 CSS 這一塊。

閱讀更多

前言

要學習一個新的東西,光用看的還真的沒什麼用,直接動手下去做才是比較好的方法。因為上一份工作快離職時 React hook 才剛出來,所以我之前從來沒寫過 hook,只有看過一些基本的教學而已。而前陣子開始工作之後,才終於開始寫 function component + hook。

雖然剛開始還是滿懷念 class 的寫法,但寫久之後覺得 hook 也挺不錯的。在使用 hook 的過程中也有碰到一些剛轉換的人常碰到的問題,仔細研究後發現這篇文章要提的案例還滿不錯的,如果能夠理解這個案例,應該就可以掌握到 class 與 function component 根本上的不同,因此寫了這篇來記錄一下心得。

話說如果你已經寫 function component 一陣子,hook 也用得滿習慣的,而且都有把官方文件還有 dan 哥的文章好好看過,基本上不會從這篇文章獲得任何新知識。這篇適合的對象是剛轉換到 function component,而且不太確定跟 class 的差異是什麼的人。

閱讀更多

前言

前陣子看到了這個寫得很棒又很漂亮的教學:Regular Expressions for Regular Folk,再加上之前一直沒有在自己的課程裡面教到 Reglar Expresioon,可是這在開發上又滿常見,於是決定寫一篇文章簡單講一下這個主題。

因此呢,這篇是給完全不懂這是什麼的初學者看的,所以會講得滿淺的,會帶到的例子應該也都是相對簡單的東西,模式也比較固定,需要考慮的邊界條件少很多,學習起來我認為也會比較容易。

好,接下來就開始吧!

閱讀更多

前言

如果有先寫過其他 function 不是 first-class 的程式語言,在寫 JavaScript 的時候應該會經歷一些陣痛期,想說到底在做什麼——至少我是這樣的。

我當初發現可以把 function 當作參數到處傳遞的時候,對於比較複雜的 code 就要想很久,而 function 的其他行為也是讓我一頭霧水,例如說 function 居然也是 object,還有 this 到底是什麼鬼東西。

這一篇主要是想分享一些我覺得 function 比較有趣的地方。可是呢,直接開始講一大堆知識太無趣了,我希望能引起大家對這些知識的好奇程度,而想要引起好奇,最好的方法就是提供一個「你也會感興趣的問題」,你就會有動力繼續往下看了。

因此底下就以幾個小問題作為開場,雖然是問題的形式,但答不出來也完全沒有關係,如果你對這些問題的答案有興趣的話再往下看,沒興趣的話出口直走到底左轉。

話說這篇標題本來想取叫:「JavaScript function 知多少」或是「有趣的 JavaScript function」,但這種標題太無趣了,所以才想到這種輕小說式(?)的標題。

閱讀更多

前言

會寫這篇是因為我相信一定很多人都碰到過這個問題,簡單一句話總結就是:「用console.log 印出物件時,印出的值跟想像中不一樣」,我們來看看底下的程式碼:

閱讀更多

前言

先稍微介紹一下什麼是 Online Judge(底下簡稱 OJ)系統,簡單來說就是像 leetcode 那樣啦,可以送出程式碼解題,然後讓系統去批改,並且得到最後的結果。底下是 leetcode 的截圖:

leetcode 介面

在 leetcode 流行以前,最知名的 OJ 大概就是 UVa Online Judge,俗稱 ACM,而台灣的話應該就是 ZeroJudge 比較有名。

如果剛好有需求,想要自己架一個 OJ 的話,該怎麼辦呢?

閱讀更多

前言

在我以前寫過的兩篇文章:我知道你懂 hoisting,可是你了解到多深?以及所有的函式都是閉包:談 JS 中的作用域與 Closure 裡面,都談到了 let 與 var 作用域的不同。

let 的作用域是 block,而 var 則是 fucntion,像這個就是經典案例:

for(var i=1; i<=10; i++) {
  setTimeout(function() {
    console.log(i)
  })
}

原本預期會依序輸出 1~10,沒想到卻輸出了 10 個 11。背後原因就是因為第三行那個 i 永遠都只有一個,就是 for 迴圈宣告的那個 var i,從頭到尾都是同一個變數。

而經典解法也很簡單,把 var 改成 let 就搞定了:

for(let i=1; i<=10; i++) {
  setTimeout(function() {
    console.log(i)
  })
}

搞定的原因是,可以把上面程式碼看作是下面這種形式:

{
 let i=1
 setTimeout(function() {
    console.log(i)
  })
}

{
 let i=2
 setTimeout(function() {
    console.log(i)
  })
}

...

{
 let i=10
 setTimeout(function() {
    console.log(i)
  })
}

由於 let 的作用域是 block,所以在每一圈迴圈裡面,其實都是一個新的 i,因此迴圈跑 10 圈就有了 10 個不同的 i,最後當然是輸出 10 個不同的數字。

因此 var 跟 let 在這個範例最大的區別就在於變數的數量,前者只有 1 個,後者卻有了 10 個。

好,既然知道了 let 與 var 的差別以後,就可以來看看這篇最主要想討論的問題。

其實這問題是來自於 YDKJS(You Dont Know JS,中譯本翻做:你不知道的JavaScript) 的作者 @getify 在他的推特上所提出的:

question for JS engines devs…
is there an optimization in place for this kind of code?

for (let i = 0; i < 10; i++) {
  // no closure
}

IOW, where the behavior of creating a new i per iteration is not needed nor observable… does JS skip doing it?

若是沒有看得很懂,可以繼續看延伸的另外一則推

here’s a variation on the question… will JS engines exhibit much performance difference between these two loops?

for (var i = 0; i < 100000000; i++) {
   // do some stuff, but not closure
}

for (let i = 0; i < 100000000; i++) {
   // do the same stuff (no closure)
}

簡單來說呢,平常用 let 搭配迴圈的時候,不是如我們上面所說的,每一圈都會有一個新的i嗎?既然是這樣的話,那 var 與 let 應該就會有效能上的差異,因為 let 必須每一圈都 new 一個新的變數出來,所以 let 會比較慢。

那如果迴圈裡面並不需要每一圈都有新的 i,JS 引擎會做優化嗎?這個問題就是這樣,主要是想探討 JS 引擎會不會針對這種行為去做優化。

那要怎麼知道呢?要嘛你是 JS 引擎的開發者,要嘛你去看 JS 引擎的原始碼,但這兩種難度都有點太高。不過別擔心,還有第三種:看 JS bytecode。

閱讀更多

前言

在我的部落格裡面,其實很少有工具類的教學文章。一來是因為這種工具類文章都大同小異,二來是我生性懶惰,許多手把手教學都需要鉅細靡遺外加豐富截圖,實在是不適合我。

但這次會來寫這個題目,是因為我覺得 webpack 是個新手不容易懂,就算懂了也不一定是真的懂的工具。或是換句話說,它是常常被誤解的一個工具。

這並不是 webpack 本身的問題,而是現在許多新手切入前端都直接從 React 或是 Vue 開始,而且都使用了他們各自提供的 CLI 工具,等到要客製化一些設定時才注意到:「阿,原來有個東西叫做 webpack」。

CLI 工具帶來了方便性,優點是讓新手能夠快速上手,不用去管那些繁瑣的設定;而缺點就是若是新手沒有意識到背後那些工具,等到哪一天工具壞了、不能用了或是有地方需要修改,就是噩夢的開始。

為了讓這種情況減少,我才決定寫這篇文章,希望從源頭帶大家認識 webpack 這項工具以及模組化的概念。你必須先知道什麼是模組,才能理解什麼是 webpack。

開頭我想先透過幾個問題讓大家思考自己對模組化以及 webpack 是否熟悉:

  1. 為什麼很多專案(例如說 React)在部署前都要先 build?這個步驟在幹嘛你知道嗎?
  2. 你知道 require/module.exportsimport/export 的差別嗎?
  3. 你知道 import 與 export 這兩個語法在瀏覽器上面不是隨便就能使用嗎?
  4. 你知道為什麼要用 webpack 嗎?
  5. 你知道 webpack 為什麼要有 loader 嗎?

這些問題應該會在讀這篇文章時慢慢有點靈感,在最後面時會幫大家解答。

閱讀更多