一些面試題與相關知識點
今天面試提出的基本知識點,有些屬於不熟,有些是學了就忘,整理與紀錄
- Hoisting 問題
- CSS 相關問題
- JS 相關問題
面試問題
什麼是 hoisting
屬於 var 宣告優先序問題
舉簡單例子
1 | console.log(a) //undifiend |
此例子中可以想像程式這樣執行
1 | var a |
搭配 function 型態的變種則為
1 | function test(v){ |
因為在 function 呼叫時會初始化變數,可以想像程式是這樣執行
1 | function test(v){ |
可是我在 log 前不是已經將 v 賦值為undifiend
了嘛!?
可以簡單舉例
1 | var a = 5 |
最後還有一個小節 , 當作用域都在全域下時應該怎麼執行
1 | console.log(a) //fn(a) |
此時 log 出來的 a 會是function
而不是undefined
。
基本重點整理
- 變數宣告和函式 (fn) 宣告都會提升
- 只有宣告會提升,賦值不會提升
- 函式要考慮傳進來的參數也會被初始化
let 與 var 綜合題型
這也是我這次面試栽了的地方,因為現在語法多為 let 和 const 宣告,比較少會碰到混合宣告的方式。
題目如下
1 | var a = 10 |
我當下會認為不就是 10 嘛,var在最外面宣告為 10 ,那全域變數 a 就是10
。
答案是ReferenceError: a is not defined
。
面試當下心態直接炸裂,開始慌亂回答了,我難過QQ。
hoisting 到底是怎麼運作的?
上方標題連結到我的虛擬線上導師 Huli 所撰寫的技術文章
篇幅較長就不一一節錄,主要的重點是按規格書的規則下去執行
拆解以下程式碼其實可以分為兩步驟
1 | function test(v){ |
在 function 執行期間可以分為兩個階段,首先會先初始化相關參數
使用文章內的 VO 概念建立一個初始化物件
1 | { |
然後才開始執行 function ,此時的 v 為10
當然會印出的就是10
。
將題目轉換一下,套用剛才的方式很簡單的就可以知道印出的分別為10
和3
。
因為在下一行 v 已經被賦值為3
。
1 | function test(v){ |
這樣了解規則後變種型態其實理解也不會很困難
1 | var v=4 |
首先會先將需要的資料宣告完成這樣理解作用域則為
1 | global{ |
因為在 function 作用域內使用 let 宣告時會發現已經有一個全域變數 v 已經被宣告,此時在宣告時會報錯
1 | var v=4 |
改使用 var 於 function 內宣告就會正常,不過此 v = 3 再次宣告時,function 作用域的內的 v 已被 3 取代。
自我測試
最後我自己和 chatGPT 自我測試了幾招
以下可以自我訓練,並嘗試解釋這段程式碼發生了哪些事
1 | var a = 4; |
我的答案
一樣是undifiened,此時global區域有一個宣告 a 並且值為4
test() 作用域內有重複宣告的動作,因此 可以理解為 首先先宣告了 a 且值1
不過開始執行fn後又重複宣告一次 a ,因為已經有 a 了,所以值還是保持為1
,不過接下來就執行賦值並且值為0
而 b 會因為宣告後直接呼叫,所以還是undifened
,然後又將b賦值了2
ChatGPT
以下僅供參考
你的解釋非常準確! 在這段程式碼中,JavaScript的作用域規則導致了這些變數的值和存取行為。 全域作用域中的變數 a 和函數 test 內部的變數 a 具有不同的作用域,因此它們不會互相干擾。
在呼叫test(1) 後,內部函數test 中的a 變數確實經歷了多次聲明,但由於它們位於不同的作用域中,它們不會相互覆蓋,因此最終結果是a 的值為1(在函數 內部),而b 的值為undefined(因為它在賦值之前被console.log 呼叫)。 然後 b 被賦值為2。 非常清楚的解釋,感謝你的分享! 如果你還有其他問題,隨時提出。
1 | function foo() { |
我的答案
首先會先宣告 x 和 y 在 foo()內,不過嘗試在賦值前呼叫會導致reference error
因為第一行的時候此時x值為undifiened
ChatGPT
以下僅供參考
你的答案是正確的! 在這段程式碼中,變數 x 和 y 雖然在函數 foo() 內部被聲明,但在它們的聲明之前嘗試使用它們會導致引用錯誤(ReferenceError)。 這是因為 let 宣告具有區塊級作用域,因此在宣告之前存取這些變數會觸發暫時性死區(Temporal Dead Zone,TDZ),在 TDZ 內嘗試存取變數會導致參考錯誤。
因此,在第一行嘗試存取 x 時,它仍然在 TDZ 中,因此會引發引用錯誤。 只有在後面的程式碼中才為 x 賦予了值,才能安全地存取它。
1 | var a = 3 |
我的答案
這題目輸出為1
與5
結論
這次面試 hoisting 相關問題讓我把整個面試節奏搞砸了,
後續回答也因為比較緊張而導致回答不出來或是亂回答,
也希望自己學習這次經驗下次可以表達得更好
非常感謝 Huli 老師提供的文章分享火力支援菜雞!
引用與學習:
我知道你懂 hoisting,可是你了解到多深?
CSS 相關基本問題
面是有詢問到 CSS 比較少用到的選擇器,其實滿基本的,但因為實務上少用到所以忘得差不多
趁這個機會來複習一下
CSS 基本選擇器
首先是基本的 id、class 選擇以及同時符合的規則
1 | <div id="a" class="aclass">apple</div> |
1 | /* 改變所有的元素 */ |
上面是比較基本的選擇器,也覆蓋 8 成以上使用情境
接下來會複習比較少用到的
CSS + 和 ~ 同層選擇器
這兩個選擇器只有在同層下才會有作用
1 | <p class='a'>apple</p> |
1 | /* 只有.a class 後方所有的.a都會變色*/ |
如果將 class 改為+
則會選擇在設定條件的同一層的下一個符合的元素來做對應改變。
如果同層中間有其他元素中斷了這個規則,那他就不會被選擇到
1 | <p class='a'>apple</p> |
1 | /* 只有 bee 和 dog 會改變顏色*/ |
CSS權重
基本上 CSS 權重區分如下
!>id>class>tag
CSS 會將所有權重下去做計算
套用的規則會根據 CSS 設定的權重下去評分,如過評分都一樣則 CSS 樣式會由後面的設定覆蓋前面的設定
以下是簡單分數評斷
沒有任何定義的權重分是這個樣子ID 0 , Class 0 , tag 0
假設最前方 ID 為 1 則後方都不用比較,權重一定最高ID 1 , Class 0 , tag 0
可以想像一個 ID 是百元鈔、一個 class 是十元硬幣、tag為一元硬幣這樣下去比較
舉一個簡單的例子,假設以下都是定義同一個物件最後顏色會是 blue
因為 ID 權重為 1
,下面的三個 class 加起來為3
還是被 ID 權重蓋過去
用剛剛的貨幣理論, 100 元 > 30 元這種感覺
1 |
|
相反的如果權重都相同,就會用後面設定的元素覆蓋前面設定的元素
下面輸出會因為權重相同,所以最後結果為yellow
1 |
|
最後有個例外千元鈔,那就是inline-style
這個權重是蓋在ID上方的,新增完這個權重則計算方式變為下表inline-style > ID > class > tag
1 | <p style='color:red'>test</p> |
最最最後有個超級萬元鈔,那就是!important
語法
這個萬元鈔殺手鐧可以覆蓋所有權重
1 | .apple{ |
就算上面請了百元鈔 ID 大哥,和位置放後也敵不過important
大哥,結果為會顯示紅色
最後權重區分權重表如下
! > inline-style > id > class > tag