簡單理解
var zm = function (x) { var code = `bb` return code };
學過js的老哥們都知道,當這樣簡單的一個函式進入瀏覽器,瀏覽器開始解釋程式碼,會將window
分兩個模組:儲存模組、執行模組。
儲存模組,找到所有的var
和function
關鍵字,給這些變數新增記憶體地址
執行模組,程式碼從上到下執行,遇到變數就回去儲存模組查詢是否有該變數
如果有該變數,就看是否賦值,如果賦值了就是後面的值,沒有賦值就是undefined
如果沒找到 結果就是xxx is not defined
對於作用域可能對於部分人來說是難以理解的知識點,今天呢就列舉5個知識點,只要記住這幾句話,作用域對你來說就是小意思
一、“JavaScript中無塊級作用域”
在Java或C#中存在塊級作用域,即:大括號也是一個作用域。
public static void main (){ if(1==1){ String name = "seven"; } System.out.println(name); } // 報錯
在JavaScript語言中無塊級作用域
function Zhoumao() { if(1 == 1){ var name = `晝貓` } console.log(name); } Zhoumao()
// 輸出:晝貓
補充:標題之所以新增雙引號是因為JavaScript6中新引入了 let 關鍵字,用於指定變數屬於塊級作用域。
二、JavaScript採用函式作用域
在JavaScript中每個函式作為一個作用域,在外部無法訪問內部作用域中的變數。
function Zhoumao() { var name = `晝貓` } Zhoumao() console.log(name); // 報錯:ReferenceError: name is not defined
三、JavaScript的作用域鏈
由於JavaScript中的每個函式作為一個作用域,如果出現函式巢狀函式,則就會出現作用域鏈。
name = `晝貓` function out() { var name = `zhoumao` function inner() { var name = `hello` console.log(name); } inner() } out()
如上述程式碼則出現三個作用域組成的作用域鏈,如果出現作用域鏈後,那麼尋找變數時候就會出現順序,對於上述例項:
當執行console.log(name)時,尋找順序根據作用域鏈從內到外的優先順序尋找,如果內層沒有就逐步向上找,直到window為止,window有就使用沒有就is not defined。
四、JavaScript的作用域鏈執行前已建立
JavaScript的作用域在被執行之前已經建立,日後再去執行時只需要按照作用域鏈去尋找即可。
示例一:
name = `zhoumao` function out() { var name = `晝貓` function inner() { console.log(name); } return inner; } var code = out(); code(); // 輸出結果:晝貓
上述程式碼,在函式被呼叫之前作用域鏈已經存在:
全域性作用域 -> out函式作用域 -> inner函式作用域
當執行code()
時,由於其代指的是inner
函式,此函式的作用域鏈在執行之前已經被定義為:全域性作用域 -> out函式作用域 -> inner函式作用域,所以,在執行code()
時,會根據已經存在的作用域鏈去尋找變數。
示例二:
name = `zhoumao` function out() { var name = `晝貓` function inner() { console.log(name); } name = `hello` return inner; } var code = out(); code(); // 輸出結果:hello
上述程式碼和示例一的目的相同,也是強調在函式被呼叫之前作用域鏈已經存在:
全域性作用域 -> out函式作用域 -> inner函式作用域
不同的是,在執行 var code = out()
時,out作用域中的name
變數的值已經由晝貓
改變為hello
,所以之後再執行code()
時,就只能找到hello
示例三:
name = `晝貓`; function one(){ console.log(name); } function two(){ var name = "zhoumao"; return one; } var code = two(); code(); // 輸出結果: 晝貓
上述程式碼,在函式被執行之前已經建立了兩條作用域鏈:
全域性作用域 -> one函式作用域
全域性作用域 -> two函式作用域
當執行code()
時,code
代指的one
函式,而one
函式的作用域鏈已經存在:全域性作用域 -> one
函式作用域,所以,執行時會根據已經存在的作用域鏈去尋找。
五、宣告提前
在JavaScript中如果不建立變數,直接去使用,則報錯:
console.log(name) // 報錯:ReferenceError: name is not defined
如果只建立不賦值,則返回undefined
var name; console.log(name) // 輸出:undefined
在函式中如果這麼寫:
function Test() { console.log(name); var name = `晝貓`; } Test() // 輸出:undefined
在上述程式碼中不報錯而是輸出undefined
,是因為JavaScript的函式在被執行之前,會將其中的變數全部宣告,而不賦值。所以,相當於上述示例中,函式在“預編譯”時,已經執行了var name
;所以上述程式碼中輸出的是undefined
。
類似這種寫法
function Test() { var name console.log(name); name = `晝貓`; } Test()
文章來自公眾號 晝貓筆記