JavaScript 核心觀念(45)-函式以及 This 的運作-總結:函式的常見陷阱題
前言
接下來這章節將會集中介紹一些常見的函式陷阱題目唷~
函式的常見陷阱題
首先在課程開頭有介紹到一個粉絲專頁叫做 LevelHunt,這個粉絲頁我稍微繞了一下其實有相當多種語言的考題,其中也包含 JavaScript 考題。
雖然依照我稍微看一下來講,其實還是比較多偏向 JavaScript (JavaScript 比較奇妙吧 xD)。
那麼回來這章節其實也就會從 LevelHunt 裡面挑幾題來介紹,舉例來講以下第一題
1 | var myName = 'Global'; |
這一題答案是 Global
其主要原因是 this
是直接透過 sample call 呼叫,因此就必定會指向到 window
。
接下來第二題
1 | var myName = 'Global'; |
這題答案是 Global, 0, 1, 2
,首先在前面章節有說過 bind
函式如果在一開始沒有傳入特定參數,那麼就可以後來在傳入,但是也會因此佔用其中一個參數也就是參數 a
,而 bind
的第一個參數都是要設定 this
的指向,而在此因為沒有設置,因此就不會傳入,因此就會形成 simaple call。
那麼額外說明一下,如果希望答案是 null
的話則必須使用嚴格模式
1 | var myName = 'Global'; |
接下來第三題
1 | var value = 'Global'; |
看一題老實講有點特別,但是實際上並沒有那麼困難,首先第一個 this
是定義在 foo
物件下宣告的,因此結果就會是 local
。
第二個 console
答案則是 Global
,首先因為賦予直回去之後並沒有執行,因此在賦予之後才執行,因此就會形成 simaple call,而這部分觀念最主要與表達式有關,因此就是表達式回傳之後在執行,因此當你輸入 foo.bar = foo.bar
其實會出現 function() { return this.value; }
因此我們其實是這直接呼叫該函式,因此這一段概念就跟 a = b = 1
是非常雷同的。
那個第二個觀念也是一樣的,只是加上的運算子 ||
,而 ||
的條件中當第一個為 false
那麼就會回傳第二個,因此就結果一樣會形成 simaple call。
而這邊額外補充一個小題目
1 | var b = {}; |
之所以會講第二個與第三個與表達是有關的原因在於,若你將題目修改成以下,你會發現結果依然是 Global
1 | var value = 'Global'; |
因此這一段賦予值的過程,就是一個表達式,因此實際執行是執行表達式的結果,而不是賦予值得結果。
那麼接下來看看第四題
1 | var arr = ['1', '2', '3'].map(parseInt); |
這一題答案會是 '1', NaN, NaN
,那麼為什麼是這樣呢?首先 parseInt
可以將輸入的字串轉換為整數,而他很特別的地方在於,若你沒有指定進位的話,就會發生一點事情,這邊擷取 MDN 部分說明
從 2 到 36,能代表該進位系統的數字。例如說指定 10 就等於指定十進位。一定要定義這個參數以避免他人的困惑、也好預估函式的行為。如果沒有指定 radix 的話,給出的結果會按照實做不同而異,請注意,通常預設值不是 10 進位。
除此之外在這邊其實 map
是一個 callback function,因此會傳入餐個參數,分別是 陣列的值、陣列索引以及陣列本身,所以還原一下實際運作結果就會像下方這樣
1 | var arr = ['1', '2', '3'].map(function(item, index) { |
剛剛有說到 parseInt 第二個參數在 MDN 上是進位的意思,而第一次執行程式碼時就會是這樣子 parseInt(1, 0);
而在此並沒有 0
進位,因此就會改走預設值,這邊也直接擷取 MDN 對於這一段的說明
如果 radix 是 undefined 或 0(或留空)的話,JavaScript 會:
如果 string 由 “0x” 或 “0X” 開始,radix 會變成代表十六進位的 16,並解析字串的餘數。
如果 string 由 0 開始,則 radix 會變成代表八進位的 8 或十進位的 10,但到底會變成 8 還是 10 則取決於各實做。 ECMAScript 規定用代表十進位的 10,但也不是所有瀏覽器都支持。因此,使用 parseInt 時一定要指定 radix。
如果 string 由其他字串開始,radix 就會是十進位的 10。
如果第一個字串無法被解析為任何數字,parseInt 會回傳 NaN。
因此當若為預設值時,就有可能是瀏覽器的預設值,通常可能是 8 進位或者是 10 進位,也因此在傳入這個值的時候他就可以正確地轉換出 1
。
當執行第二個時,就會變成 parseInt(2, 1);
,因此當進位模式是 1
的時候,每數值到達 1 的時候,就會進位到下一位,因此就無法正常轉換,因此答案就是 NaN
。
那麼當執行第三次時,結果也是類似的 parseInt(3, 2);
,觀念與前者相同,當進位是 2 的時候,數值每次到達 2 就會進位到下一位,因此 3
並不存在(當然也包含 2 本身)。