前言

如果有先寫過其他 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 嗎?

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

閱讀更多

前言

一直以來我都很推薦一門課叫做 CS50,原因是又深又廣,而且教得深入淺出,作業又紮實,是很棒的一堂課。

而今天要介紹的這門課,我會形容它是「電腦底層版的 CS50」。

From Nand to Tetris 由兩位教授 Shimon Schocken 與 Noam Nisan 開設,與 CS50 一樣,一開始都是大學的課程,後來才轉為線上課程,在官網上這堂課還有一個副標題:「Building a Modern Computer From First Principles」,沒錯,要建一台電腦出來。

這堂課分為兩個部分,Part1 是 From Nand To HACK,Nand 是一個邏輯閘的名稱,就像 Or、And、Xor 這些也都是邏輯閘。而 HACK 是在 Part1 最後會建造出來的電腦。因此 Part1 就是帶你從最基本的邏輯閘開始,一步步把一台電腦建立出來,所以是很偏向硬體的部分。

Part2 則是 From HACK To Tetris,以電腦為基礎往軟體去延伸,會介紹到 Compiler 與作業系統等等的軟體。

閱讀更多

前言

最近 YDKJS(You Don’t Know JS 的縮寫,中譯版翻成:你所不知道的JS)有了第二版,名叫 YDKJSY,Y 是 Yet 的意思(中文版可能可以翻叫:你還是不知道的 JS)。這個第二版還沒全部完成,但在 GitHub 上面已經公開了最前面的一些章節。

搶先讀了一下第一章,在講與 JS 相關的歷史,其中提到一段讓我很感興趣的議題:

As such, sometimes the JS engines will refuse to conform to a specification-dictated change because it would break that web content.

In these cases, often TC39 will backtrack and simply choose to conform the specification to the reality of the web. For example, TC39 planned to add a contains(..) method for Arrays, but it was found that this name conflicted with old JS frameworks still in use on some sites, so they changed the name to a non-conflicting includes(..). The same happened with a comedic/tragic JS community crisis dubbed “smooshgate”, where the planned flatten(..) method was eventually renamed flat(..).

大意是在說有時候 JS 的規格必須跟現實(已經存在的那些舊的實作)妥協。例如說原本 Array 要加上一個叫做 contains 的 method,但因為會有問題所以改叫 includes,flatten 也改名叫做 flat。

還有一個上面特別標起來的詞「smooshgate」,用這個當關鍵字去找才發現是去年三月左右發生的事件,至於發生了什麼,底下會詳述,跟上面提的 flatten 有關。看到有這件事的時候我第一個反應是:「咦,我怎麼什麼都不知道?」,查了一下繁體中文的資料,大概也只有這篇有提到:SmooshGate,以及[筆記] 3 種 JavaScript 物件屬性的特性這篇有擦到邊而已。

在仔細研究了一下事情的來龍去脈之後,覺得是個滿有趣的議題,因此寫了這篇跟大家分享。

閱讀更多

前言

在這兩三年之間,「刷題」似乎成為了一種風潮。本科系要去面試大公司的時候要刷題,非本科系出去面試也要刷題,好像只要沒有刷題就會落後他人,就會被公司刷掉。

其實我一直不是很喜歡「刷題」這個詞,主要是因為「刷」這個字。不知道大家對這個字的解讀是什麼,但我會認為有種「為了寫題目而寫題目」的感覺,就好像題海戰術那樣。雖然說題海戰術用得好的話成效滿顯著的,但總感覺很多人刷到最後會變成「看過的題目就會,沒看過的就一定不會」,如果是這樣子的話,那我覺得不是一件好事。

之前我有寫了一篇文章:當我們在學程式時,要學的到底是什麼?,稍微談了一下這件事情。

總之呢,比起刷題這個詞,我更喜歡用「程式解題」四個字來表達我想表達的意思。

閱讀更多

前言

如果要舉出一個在 JavaScript 裡面很重要也很常用,但新手常常搞混的概念,那「非同步(Asynchronous)」當仁不讓,絕對是第一名。跟其他那些 thisclosureprototype 或是 hoisting 比起來,非同步在實際開發的時候用到的頻率高太多了,而且是初學者常常會踩坑的地方。

非同步真的那麼難嗎?

我相信不是的。只要循著一個正確的脈絡前進,就可以循序漸進理解為什麼需要非同步,也能知道在 JavaScript 裡面是怎麼處理這種操作的。

類似的主題我其實在四年前就寫過,但現在回頭看實在是寫得滿差的,所以四年後重新挑戰這個主題,希望能寫出一篇品質不錯的文章,把非同步這件事情講清楚。

在寫這篇文章之前,參考了 Node.js 的官方文件,發現在非同步的講解上其實做得不錯,因此本文會以類似的切入點開始談這個問題。如果不會 Node.js 也沒關係,我底下會稍微做點介紹。

建議閱讀本文以前需要具備 JavaScript 基礎,知道如何使用 JavaScript 操作 DOM,也知道什麼是 ajax。

接著就讓我們開始吧!

閱讀更多

大約在一年前的時候,我把 Blog 直接放在 GitHub Issues 上面。雖然說台灣很少人這樣做,但有許多中國的開發者都利用這個方式來架 Blog。

那時我會想採用 GitHub Issues 的原因很簡單,就是因為方便。

  1. GitHub Issues 完美支援 Markdown 語法。
  2. 上傳圖片超方便
  3. 當別人也用 Issues 提到你的文章時,會自動產生 reference
  4. 留言系統超方便
  5. 可以按 Emoji
  6. GitHub repo 可以按 watch 來關注,更新時會收到通知

總結以上,當時選擇了 GitHub Issues。

但最近發現一個很大的問題,當初沒有注意到,那就是 GitHub Issues 的 SEO 極差。你直接拿 Issue 的標題去 Google 搜尋,還不一定能搜得到。

因為這問題挺大的,所以最後還是搬回了 Hexo。

兩年前其實我就已經搬過一次家了,從 Logdown 搬到 Hexo 去。但那時我沒有繼續使用 Hexo,因為我覺得那個部落格的版面不太好看。

而這次重新搬回來,很大一部分是因為看到了 Askie Lin 的部落格,我看到的時候驚為天人,想說:「哇,這部落格也做得太漂亮了吧!」,後來得知是使用現成的主題 Minos 來改的,於是我就想說可以換成這個主題試試看。

今天經過一整天的調整,自己修了滿多東西,試著把這個版型修成自己想要的樣子,發現還滿順利的。可能是因為原本的 code 就寫得不錯,基本上修起來沒有太大問題,改了一下字體大小以及分類跟文章列表顯示的樣子,其他都沒什麼動。

沒什麼意外的話,以後就決定在這邊紮根了,原本 GitHub 那邊就當作備份文章的地方好了。

Hexo 萬歲,Minos 萬歲 🎉