常讓人誤解的一道js小題


 一道小題引發的深思    

     今天無意中看到一個js筆試題,不由得想起初學js那會被各種題目狂虐的心酸,雖說現在也會被筆試題所虐,但畢竟比之前好了很多,下面就是我的個人理解,歡迎拍磚、指正:

var x = 1;
function printx(){
    console.log(x);
    
}

function show(f){
    var x = 2;
    (function(){
        f();
    })()
}

show(printx); //1 

     結果后台會打印1,而不是2。這有些不合常理,因為很多人會錯誤的認為:函數show中的f()在執行時,由於本作用域中沒有x,所以會向上層作用域尋找x,當找到上層函數show的作用域中時發現 var x=2,這時就把x確定為2,否則會繼續向上找,直至window。。。終於用到所謂的“作用域鏈”啦!大喜,其實這樣想你就錯了!

   第一:首先有這么一個名詞叫“自由變量”,自由變量是指:如果作用域(函數)A中使用到了變量x,而x並不是在作用域(函數)A中定義,那么對於作用域(函數)A來說,x就是A的自由變量。

   第二:理解這么一句話:js沒有塊級作用域,僅有的塊級作用域是用函數來實現的,也就是說只有函數能創建出一塊獨立的作用域。if、for代碼塊都不行!所以本文中一個作用域可以理解為一個函數。

   第三:函數的作用域在函數定義時就已經確定,而不是在執行時確定。

    對於嵌套函數來說按照上述:尋找自由變量是沿作用域鏈向上一層層查找,這樣理解是對的。但是這樣理解太片面,甚至會產生錯誤,就比如上面這道題。正確的理解應該是:尋找自由變量時會到創建這個函數(作用域)的那個作用域中尋找。而創建這個函數的作用域並不一定是它位置上的父級作用域,(並不是在代碼結構上包含,就是子父關系)上面這道題就是這種情況:函數show中把printx函數作為參數傳入執行,在執行時會尋找創建它的那個作用域,很明顯創建printx函數的作用域並不是show,而是全局window(因為printx函數在window中創建),所以它會尋找全局window中的x,此x為1。 所以會打印1,這才是正解。

      不知道我解釋的清不清楚,總之:函數使用自由變量時,會到創建這個函數的那個作用域中尋找。“向父級作用域中尋找”可能會存在偏差。(不足之處歡迎指正!)

 再補充兩道,加深理解

     本文的評論里還有兩道更加通俗易懂的兩道題,征得熱心博友theWalker的同意,把他給出的兩個demo也展示給大家,希望對你有所幫助:

function a(){
  console.log(b)
}
function c(){
  var b = 1;
  a()
}
c() //b is not defined

 /****************************************/

var b = 2;
function a(){
  console.log(b)
}
function c(){
  var b = 1;
  a()
}
c() // 2

 


免責聲明!

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



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