本文在 "個人主頁" 同步更新~ 背就完事了 介紹:一些知識點相關的面試題和答案 使用姿勢: 看答案前先嘗試回答,看完後把答案收起來檢驗成果~ 面試官:如何理解JS的作用域和作用域鏈 答:在ES5中,只有全局作用域和局部作用域。ES6因為let,const的引入而有了塊作用域。js在瀏覽器中的頂級作 ...
本文在個人主頁同步更新~
背就完事了
介紹:一些知識點相關的面試題和答案
使用姿勢:看答案前先嘗試回答,看完後把答案收起來檢驗成果~
面試官:如何理解JS的作用域和作用域鏈
答:在ES5中,只有全局作用域和局部作用域。ES6因為let,const的引入而有了塊作用域。js在瀏覽器中的頂級作用域是window。作用域鏈的話,是指子作用域會一級一級向上尋找所有父作用域的變數。 解析:1. 局部作用域所對應的是函數環境,塊作用域對應的是大括弧({ ... })內的環境,如if,for,switch等;2. 作用域鏈簡單理解為函數嵌套時,內層函數可以訪到上層函數的作用域,而上層又可以往上上層找,從而形成鏈式結構。面試官:什麼是變數提升
答:在js中,所有變數和函數的聲明都會被提升到所在作用域的最頂部,所以變數先使用,後聲明是不會報錯的。 解析:註意是所在作用域而不是最外層。面試官:var和let, const有什麼區別
答:var聲明的變數沒有塊作用域,在最外層聲明的話會掛在到window上,並且存在變數提升;let和const聲明的是塊級變數,不會掛載到window上,也不存在變數提升,而且不能重覆聲明同一個變數;const聲明的變數不能被重新賦值,一般用來聲明常量。 解析:const聲明的變數雖然不能被重新賦值,但並不意味著他的值不能被改變。例如當const聲明的變數是引用類型的時候。面試官:什麼是閉包
答:閉包是一個可以訪問到其他函數內部變數的函數。 解析:常見於函數嵌套,子函數可以訪問到父級函數作用域下的變數,則子函數稱為閉包。面試官:閉包有什麼作用和缺點
答:閉包的作用有兩個,正常來說,函數作用域外部無法訪問到內部的變數,而閉包可以作為橋梁讓外部能成功訪問到函數的變數;第二個是能使函數變數的值一直保存在記憶體中。缺點的話就是可能引起記憶體泄漏,在函數執行完畢後,可能因為閉包導致外層函數的變數一直存在記憶體中。 解析:閉包的第一個作用可以理解為,java中的getter方法,外部只能通過getter(閉包)來訪問對象(函數)中的私有變數(變數)。理解小幫手
介紹:總結性的圖表或筆試題目和解析,讓知識點更容易懂
關於作用域,作用域鏈,以及變數提升和var,let,const和閉包的相關知識
下麵通過代碼分析來加深認識
註: 建議將複製到瀏覽器控制台,或者node環境下執行,手機的話建議橫屏~
var count = 0 // 用來標識列印的序號
console.log(++count, song) // 輸出:1 undefined 解析:變數提升
// console.log(++count, artist) // 報錯:'artist'不能在變數聲明前使用 解析:let沒有變數提升
var song = '說好不哭'
let artist = '奶茶倫'
const favorite = '奶茶'
const girlfriend = {
name : '蔡依林'
}
console.log(++count, window.song) // 輸出:2 說好不哭 解析:最外層用var聲明會掛載到window上
console.log(++count, window.artist) // 輸出:3 undefined 解析:let聲明不會掛載到window
for(var i = 0; i < 10; i++ ) {} // 在for中用var聲明變數i
for(let j = 0; j < 10; j++ ) {} // 在for中用let聲明變數j
console.log(++count, i) // 輸出:4 10 解析:var沒有塊作用域
// console.log(++count, j) // 報錯:j沒有被定義 解析:let有塊作用域
// favorite = '咖啡' // 報錯:常量被賦值 解析:const聲明的變數不能被重新賦值
girlfriend.name = '昆凌'
console.log(++count, girlfriend) // 輸出:5 {name:'昆凌'} 解析:const聲明的引用類型可以被改變
function cooperate () {
console.log(++count, song) // 輸出:6 說好不哭 解析:作用域鏈,往上層作用域找song
var feat = undefined
function getFeat (artistName) { // 閉包 - 函數嵌套
feat = artistName
return feat
}
return getFeat // 將閉包暴露出來
}
// console.log(++count, feat) // 報錯:feat沒有被定義 解析:feat在函數cooperate的作用域中,屬於局部變數
var getFeat = cooperate() // 創建一個閉包
console.log(++count, getFeat('阿信')) // 輸出:7 阿信 解析:通過閉包成功列印cooperate函數中的feat屬性
getFeat = null // 閉包使用後需要手動釋放,不然會造成記憶體泄漏
相關筆試題思考
前端面試的筆試題或多或少會有一至兩道考核作用域的題目,如以下經典例子
function p1() {
console.log(1);
}
function p2() {
console.log(2);
}
(function () {
if (false) {
function p1() {
console.log(3);
}
}else{
function p2(){
console.log(4)
}
}
p2();
p1()
})();
解決這類問題的關鍵在於
- 將所有變數,在紙上手動提升了再說,腦補容易有疏漏
- 通過function 聲明的函數,也別忘了進行變數提升(function p1(){} 等同於 var p1 = function () {})
- 分析作用域,一般會拿var沒有塊作用域來整事
var p1; // p1 = undefined 解析:變數提升
var p2; // p2 = undefined - 變數提升
function p1() { // p1 = function () { 1 }
console.log(1);
}
function p2() { // p2 = function () { 2 }
console.log(2);
}
(function () { // 匿名函數作用域
var p1; // p1 = undefined 解析:變數提升,function p1(){} 等同於 var p1 = function () {},var沒有塊作用域
var p2; // p2 = undefined 解析:變數提升
if (false) {
function p1() { // p1 = undefined 解析:因為if(false),這塊代碼不會執行
console.log(3);
}
}else{
function p2(){ // p2 = funtcion() { 4 }
console.log(4)
}
}
p2(); // 在當前作用域找到了p2,列印4
p1() // 在當前作用域找到了p1,報錯:p1 is not a function
})();
以上!
Kane -- 一切都是命運石之門的選擇