攻略前端面試官(二):作用域和閉包


本文在個人主頁同步更新~

背就完事了

介紹:一些知識點相關的面試題和答案
使用姿勢:看答案前先嘗試回答,看完后把答案收起來檢驗成果~

面試官:如何理解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()
})();

解決這類問題的關鍵在於

  1. 將所有變量,在紙上手動提升了再說,腦補容易有疏漏
  2. 通過function 聲明的函數,也別忘了進行變量提升(function p1(){} 等同於 var p1 = function () {})
  3. 分析作用域,一般會拿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 -- 一切都是命運石之門的選擇


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM