大話javascript 1期:做用域和做用域鏈

1、什麼是做用域?

做用域是你的代碼在運行時,各個變量、函數和對象的可訪問性。(可產生做用的區域)

2、JavaScript中的做用域

在 JavaScript 中有兩種做用域前端

  • 全局做用域
  • 局部做用域

當變量定義在一個函數中時,變量就在局部做用域中,而定義在函數以外的變量則從屬於全局做用域。每一個函數在調用的時候會建立一個新的做用域。函數

1.全局做用域

當你在文檔中(document)編寫 JavaScript 時,你就已經在全局做用域中了。JavaScript
文檔中(document)只有一個全局做用域。 定義在函數以外的變量會被保存在全局做用域中
// 做用域默認爲全局做用域
var name = 'andy';

全局做用域裏的變量可以在其餘做用域中被訪問和修改code

var name = 'andy';
console.log(name); // 輸出 'andy'
function logName() {
    console.log(name); // 'name' 變量能夠在這裏和其餘地方訪問
}
logName(); // 輸出 'andy'

2.局部做用域

定義在函數中的變量就在局部做用域中。而且函數在每次調用時都有一個不一樣的做用域。這意味着同名變量能夠用在不一樣的函數中。由於這些變量綁定在不一樣的函數中,擁有不一樣做用域,彼此之間不能訪問。
// 全局做用域
function someFunction() {
    // 局部做用域 ##1
    function someOtherFunction() {
        // 局部做用域 ##2
    }
}
 
// 全局做用域
function anotherFunction() {
    //局部做用域 ##3
}

3.塊語句(JS沒有塊級做用域)

塊級聲明包括if和switch,以及for和while循環,和函數不一樣,它們不會建立新的做用域。在塊級聲明中定義的變量從屬於該塊所在的做用域。也就是說在for、if、while等語句內部的聲明的變量與在外部聲明是同樣的,在這些語句外部也能夠訪問和修改這些變量的值。
if (true) {
    //這裏的if條件不會建立一個新的做用域
    var name = 'Hammad'; // name 這個變量仍在全局做用域
}

console.log(name); // logs 'Hammad'

ECMAScript 6 引入了let和const關鍵字。這些關鍵字能夠代替var對象

var name = 'Hammad';

let likes = 'Coding';
const skills = 'Javascript and PHP';

和var關鍵字不一樣,let和const關鍵字支持在塊級聲明中建立使用局部做用域(塊級做用域)ip

if (true) 
    // 這個 'if' 塊語句沒有建立一個塊級做用域

    // name 變量處於全局做用域,由於由var關鍵字聲明
    var name = 'Hammad';
    // likes 變量處於塊級做用域由於由let關鍵字聲明
    let likes = 'Coding';
    // skills 變量處於塊級做用域由於由const關鍵字聲明
    const skills = 'JavaScript and PHP';
}

console.log(name); // 輸出 'Hammad'
console.log(likes); // Uncaught ReferenceError: likes is not defined
console.log(skills); // Uncaught ReferenceError: skills is not defined

一個應用中全局做用域的生存週期與該應用相同。局部做用域只在該函數調用執行期間存在作用域

4.詞法做用域

所謂的 詞法( 代碼 )做用域, 就是代碼在編寫過程當中體現出來的做用範圍. 代碼一旦寫好, 不用執行, 做用範圍就已經肯定好了.
這個就是所謂詞法做用域.這意味着 函數運行在定義它的做用域中,而不是在調用它的做用域中

在 js 中詞法做用域規則:文檔

  • 函數容許訪問函數外的數據.
  • 整個代碼結構中只有函數能夠限定做用域.
  • 做用規則首先使用提高規則分析
  • 若是當前做用規則中有名字了, 就不考慮外面的名字

詞法做用域

var用來將變量定義在詞法做用域中(也就是function中)it

function someFunc(){
    var a;
}

a就被函數someFunc框在了詞法做用域中io

塊級做用域

letconst用來將變量定義在塊級做用域中(也就是花括號中)console

if(true){
    let b;
}

b就被if的花括號框在了塊級做用域中

5.做用域鏈

能夠發現只有函數能夠製造做用域結構. 那麼只要是代碼, 至少有一個做用域, 即全局做用域. 凡是代碼中有函數,那麼這個函數就構成另外一個做用域. 若是函數中還有函數, 那麼再這個做用域中就 又能夠誕生一個做用域. 那麼將這樣的全部的做用域列出來,能夠有一個結構: 函數內指向函數外的鏈式結構.

做用域嵌套

做用域是能夠嵌套的,任務一中提到的詞法做用域和塊級做用域均可以嵌套其餘做用域
(塊級做用域僅對ES6而言)

function someFunc(){
    function inner(){
    }
}

inner就是嵌套在someFunc(詞法做用域)中的詞法做用域

if(true){
    while(false){
    }
}

while就是嵌套在if(塊級做用域)中的塊級做用域

function someFunc(){
    if(true){
    }
}

if就是嵌套在someFunc(詞法做用域)中的塊級做用域

做用域中的變量訪問

全部的嵌套做用域都遵循如下規則:
內部做用域有權訪問外部做用域,反之不成立。

栗子:

function someFunc(){

var outerVar = 1;
function inner(){
    var innerVar = 2;
}

}
inner有權訪問innerVarouterVar,可是someFunc只能訪問到outerVar

多重嵌套做用域

做用域是能夠任意嵌套的,可是都要遵循上面的規則。
再附加一個規則:
兄弟做用域不可相互訪問

栗子:

function someFunc(){
    function inner(){
    }
    function inner2(){
    }
}

innerinner2都是someFunc中的做用域,正如someFunc不能訪問inner們的做用域同樣,inner們之間也不能相互訪問。

做用域樹

從上向下看這個嵌套做用域,就是棵樹!
看代碼:

function someFunc() {
  function inner() {
  }
  function inner2() {
    function foo() {
    }
  }
}

看樹:

someFunc()
       |
      / \
     /   \
    /     \
   ↓       ↓
inner()  inner2()
           |
           ↓
         foo()

要記住的是:inner做用域能夠訪問外部做用域,可是反之不成立; foo()能夠訪問inner2()中的變量,inner2()能夠訪問someFunc()中的變量,這棵樹倒過來彷佛更有意義,就成了鏈!!

做用域鏈

從最裏面看到最外面就構成了做用域鏈

someFunc()
       ↑
        \
         \
          \
         inner2()
           ↑
           |
         foo()

若是你以爲這篇文章對你有所幫助,那就順便點個贊吧,點點關注不迷路~

黑芝麻哇,白芝麻發,黑芝麻白芝麻哇發哈!

前端哇發哈

相關文章
相關標籤/搜索