0%

轉職前端工程師 - JavaScript 面試題

這篇是JS的面試題,比較基本一些,也把不熟的特意列出


var、let、const 的差別?

我的作答:
var 是函式作用域,他如果寫在最外層就變成全域環境
let 是區塊作用域 , let 是可以被改變,const則不行

ChatGPT回答:

  • var 是函式作用域,也就是說,如果在函式內使用 var 定義變量,那麼該變量只能在該函式內訪問。如果在最外層使用 var 定義變量,則該變量會成為全域變量,在整個程式中都可以訪問。
  • let 是區塊作用域,也就是說,如果在某個區塊(例如函式、條件語句或循環語句)內使用 let 定義變量,那麼該變量只能在該區塊內訪問。
  • const 是區塊作用域,並且變量的值是不可變的。也就是說,一旦使用 const 定義變量,就必須立即給該變量賦值,且之後不能再改變該變量的值。

Array.forEach、Array.map、Array.filter、Array.reduce 的差別?

我的作答:
Array.forEach,會依序將Array內容依序執行函式一遍,但不會回傳任何值
Array.map,會依序將Array內容依序執行函式一遍,且每執行一次函數回傳一次值,最後回傳結果為陣列
Array.filter,會依序將Array內容依函式(可加入正規表達式篩選)執行,,且每執行一次函數回傳一次為true的值,最後回傳結果為陣列
Array.reduce,會傳入兩組參數,分別為acc, cur,函式內會依序執行acc+cur等函式,最後須給上acc預設值;通常使用在需要累加的情境,會得到累加後的結果,最後回傳結果為值

ChatGPT回答:

  • Array.forEach 方法會對陣列中的每個元素依次執行指定的函式,但不會回傳任何值。
  • Array.map 方法會對陣列中的每個元素依次執行指定的函式,並回傳一個新的陣列,新陣列的每個元素都是指定函式的回傳值。
  • Array.filter 方法會對陣列中的每個元素依次執行指定的函式,並回傳一個新的陣列,新陣列只包含函式回傳值為 true 的元素。
  • Array.reduce 方法會對陣列中的每個元素依次執行指定的函式,並按照指定的順序累加每個元素的值,最後回傳累加結果。

總的來說,Array.forEach 方法會對陣列中的每個元素執行函式,但不會回傳任何值;Array.map 和 Array.filter 方法會對陣列中的每個元素執行函式,並回傳新的陣列;Array.reduce 方法會對陣列中的每個元素執行函式,並根據指定順序累加每個元素的值


知道event bubbling和capture的事件傳遞流程嗎?

我的回答:
為事件傳遞的差別,一般預設為false是為bubbling,也就是從觸發函式的節點node到最外層,反之若設為true,則是為capture,則從最外層body傳入到最裡面node。

ChatGPT回答:

  • 事件冒泡(event bubbling)是指當發生事件時,事件會從觸發函式的節點開始,然後一層層往外傳遞。也就是說,先從觸發函式的節點處理事件,然後是其父節點,再是其父節點的父節點,以此類推,直到最外層的 body 節點為止。

  • 事件捕獲(event capturing)是指當發生事件時,事件會從最外層的 body 節點開始,然後一層層往裡傳遞。也就是說,先從最外層的 body 節點處理事件,然後是 body 節點的子節點,再是子節點的子節點,以此類推,直到觸發函式的節點為止。

在使用 addEventListener 方法添加事件監聽器時,可以使用第三個參數指事件傳遞模式。如果第三個參數為 false,則使用事件冒泡模式;如果第三個參數為 true,則使用事件捕獲模式。

為了確保程式的可維護性和可讀性,建議使用事件冒泡模式。因為事件冒泡模式是預設模式,所以通常不需要指定第三個參數。

總的來說,事件冒泡(event bubbling)是指當發生事件時,事件會從觸發函式的節點開始,一層層往外傳遞,直到最外層的 body 節點為止;事件捕獲(event capturing)是指當發生事件時,事件會從最外層的 body 節點開始,一層層往裡傳遞,直到觸發函式的節點為止。


知道 debounce 和 throttle 的差異嗎?

我的回答:
debonuce是防抖動,是防止不斷觸發某一函式,則限制只執行最後一次
throttle則是閥門,是防止函式運作時太多次的點擊,則限制觸發後固定時間後才能再次執行

ChatGPT回答:
debounce 和 throttle 是兩種用於限制事件觸發頻率的技術,通常用於頁面交互或動畫效果中。

  • debounce(防抖動)是指在事件觸發後,等待一段指定的時間,如果在這段時間內再次觸發事件,則重新計算指定的時間。通常使用 debounce 技術來防止不斷觸發某一函式,只執行最後一次。
  • throttle(閥門)是指在事件觸發後,等待一段指定的時間,如果在這段時間內再次觸發事件,則忽略該事件。通常使用 throttle 技術來防止函式運作時太多次的觸發,只在指定的時間後才能再次執行。

總的來說,debounce(防抖動)是指在事件觸發後等待一段指定的時間,只執行最後一次;throttle(閥門)是指在事件觸發後等待一段指定的時間,忽略其他觸發。


請解釋「淺拷貝」和「深拷貝」

我的回答:
淺拷貝是指物件拷貝時只複製第一層屬性,第二層則維持指向原本物件,可使用[…array]或 {…object} 做使用
深拷貝是指將物件先全部轉為JSON格式,再從字串重新轉型合併成物件,這樣可避免第二層則維持指向原本物件的狀況,可使用 JSON.stringify(obj) 以及 JSON.parse(JSONString) 搭配使用

ChatGPT回答:
在 JavaScript 中,複製(copy)指的是將一個物件或陣列複製到另一個物件或陣列中,而拷貝(clone)則是將一個物件或陣列複製到另一個新的物件或陣列中。

淺拷貝(shallow copy)是指在複製物件時,只複製第一層的屬性,第二層的屬性則維持指向原本的物件。在 JavaScript 中,可以使用 spread operator(展開運算子)或 Object.assign() 方法來實現淺拷貝。

1
2
3
4
5
6
const array = [1, 2, 3];
const shallowCopy = [...array];

const object = { a: 1, b: 2, c: 3 };
const shallowCopy = { ...object };

深拷貝(deep copy)是指在複製物件時,將物件中所有的屬性都複製到新的物件中。在 JavaScript 中,可以使用 JSON.stringify() 和 JSON.parse() 方法來實現深拷貝。

1
2
const object = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(object));

總的來說,淺拷貝(shallow copy)是指在複製物件時,只複製第一層的屬性,第二層的屬性則維持指向原本的物件;深拷貝(deep copy)是指在複製物件時,將物件中所有的屬性都複製到新的物件中。


什麼是閉包(closure)?用途是什麼?

我的回答:
JavaScript有一級語言的特性,能將函式帶入參數執行函式,就可以達到callback function的效果,而閉包就是利用函式內變數只能存在lexical environment的特性,再透過函式能變參數,就可以去訪問外部的函式取得變數

提供三個特性:
封裝私有變數
提供動態作用域
支援非同步程式設計

ChatGPT回答:
閉包是指一個函式和它所關聯的變數環境(lexical environment)。在 JavaScript 中,當一個函式被定義時,它就會有自己的變數環境。當函式被執行時,它可以訪問自己變數環境中的變數,也可以訪問它所在變數環境中的變數。因此,閉包是一種可以訪問外部變數的函式。

閉包有以下用途:

封裝私有變數:通過閉包可以將變數的作用範圍限制在函式內部,使得變數變為私有變數,只能在函式內部被訪問。
提供動態作用域:在 JavaScript 中,變數的作用域是靜態的,也就是變數的作用範圍是在變數被定義時就已經確定的。但是,通過閉包,可以實現動態作用域,即變數的作用範圍是在函式被執行時才確定的。
支援非同步程式設計:在 JavaScript 中,非同步程式設計常常使用回調函式(callback function)來實現。通過閉包,可以將回調函式和它需要的變數封裝在一起,實現非同步程式設計


在不同情況下 this 指向對象會是什麼?

我的回答:
在一般函式下,會依照呼叫函式時前方物件為何,若沒帶物件則為window,但在嚴格模式下則無效。
在箭頭函式下,則指向宣告函式時本身物件,且不會依呼叫時物件不同而改變。

ChatGPT回答:
在 JavaScript 中,this 的指向會根據函式的呼叫方式而有所不同。下面列出了幾種常見的 this 指向情況:

在普通函式中,this 指向的是被呼叫的物件。如果函式沒有被呼叫的物件,則 this 指向全域物件(在瀏覽器中是 window 物件)。

在箭頭函式中,this 指向的是函式宣告時的物件。箭頭函式不會改變 this 的指向,因此在箭頭函式中 this 的指向是固定的。

在构造函式中,this 指向的是新建的物件。构造函式是用來新建物件的函式,在构造函式中使用 this 就可以為新建的物件賦值。

在 call、apply 或 bind 方法中,this 指向的是指定的物件。這些方法可以改變函式的 this 指向,使得函式可以在不同的物件中被呼叫。


使用過什麼方法處理 AJAX?

我的回答:
AJAX為非同步執行緒,可利用XML, fetch, axios 來搭配promise 或 async/await使用,藉此讓他變成單執行緒

ChatGPT回答:
在 JavaScript 中,可以使用不同的方法處理 AJAX 請求,包括 XMLHttpRequest、fetch API 和第三方函式庫(如 jQuery 的 $.ajax() 方法)。

使用 XMLHttpRequest 處理 AJAX 請求的做法是利用 XMLHttpRequest 物件的 open() 和 send() 方法,在請求發送後檢查 readyState 屬性,當 readyState 的值為 4 時就可以取得回應。

使用 fetch API 處理 AJAX 請求的方式是利用 fetch() 函式,它可以透過 Promise 封裝回應,並且可以使用 async/await 語法來處理非同步流程。

第三方函式庫(如 jQuery)提供了簡化 AJAX 請求的方法,可以使用 $.ajax() 或是 $.get()、$.post() 等方法進行請求。

$.ajax() 方法接受一個參數,是一個物件,其中可以設定請求的設定,包括:

url: 要發送請求的位址
method: 請求的方法(預設為 “GET”)
data: 要發送的資料
dataType: 期望的回應類型(如 “json”、”text” 等)
success: 請求成功時的回調函式
error: 請求失敗時的回調函式


非同步與同步操作混用時的輸出順序?

我的回答:
先執行同步的,再執行非同步的

ChatGPT回答:
同步操作會先執行,然後再執行非同步操作。

例如,在下列程式碼中,先輸出 “Start”,再輸出 “Finish”:

1
2
console.log('Start');
setTimeout(() => console.log('Finish'), 0);

但是,如果你在非同步操作中使用了 await 關鍵字,則會等到非同步操作完成後再執行下一行程式碼。

例如,在下列程式碼中,會先輸出 “Start”,然後等待 1 秒後再輸出 “Finish”:

1
2
3
4
5
6
async function example() {
console.log('Start');
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('Finish');
}
example();

請解釋 == 和 === 的差異

我的回答:
是為嚴格等於和寬鬆等於的差別,在寬鬆下,數字型別1和文字型別1會回傳true,但在嚴格下則為false

ChatGPT回答:
在 JavaScript 中,”==” 是寬鬆相等(loose equality)運算子,它會自動將值轉換成相同的數據類型再進行比較。例如,數字 1 和文字 “1” 在寬鬆相等的情況下會被視為相等的。

相反的,”===” 是嚴格相等(strict equality)運算子,它會比較值和數據類型。因此,數字 1 和文字 “1” 在嚴格相等的情況下會被視為不相等。

總之,建議在 JavaScript 中使用 “===” 運算子。除非你有特別的需求,否則 “==” 運算子不應該被使用。