這是我參與8月更文挑戰的第12天,活動詳情查看:8月更文挑戰javascript
說明:文章部份內容及圖片出自網絡,若有侵權請與我本人聯繫(主頁有公衆號:小攻城獅學前端)前端
做者:小隻前端攻城獅、 主頁:小隻前端攻城獅的主頁、 來源:掘金java
GitHub:P-J27、 CSDN:PJ想作前端攻城獅git
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。github
直接編寫在script標籤中的JS代碼,都在全局做用域。web
全局做用域在頁面打開時建立,在頁面關閉時銷燬
。編程
在全局做用域中有一個全局對象window
,它表明的是一個瀏覽器的窗口,由瀏覽器建立,咱們能夠直接使用。瀏覽器
在全局做用域中:markdown
var a = 100
,這裏的 a
等價於 window.a
。使用var關鍵字聲明的變量( 好比 var a = 1
),會在全部的代碼執行以前被聲明(可是不會賦值),可是若是聲明變量時不是用var關鍵字(好比直接寫a = 1
),則變量不會被聲明提早。網絡
舉例1:
console.log(a);
var a = 123;
複製代碼
打印結果:undefined。注意,打印結果並無報錯,而是 undefined
,說明變量 a 被提早聲明瞭,只是還沒有被賦值。
舉例2:
console.log(a);
a = 123; //此時a至關於window.a
複製代碼
程序會報錯:Uncaught ReferenceError: a is not defined
。
舉例3:
a = 123; //此時a至關於window.a
console.log(a);
複製代碼
打印結果:123。
舉例4:
foo();
function foo() {
if (false) {
var i = 123;
}
console.log(i);
}
複製代碼
打印結果:undefined。注意,打印結果並無報錯,而是 undefined。這個例子,再次說明了:變量 i 在函數執行前,就被提早聲明瞭,只是還沒有被賦值。
例4中, if(false)
裏面的代碼雖然不會被執行,可是整個代碼有解析的環節,解析的時候就已經把 變量 i 給提早聲明瞭。
總結:
既然JS中存在變量提高的現象,那麼,在實戰開發中,爲了不出錯,建議先聲明一個變量,而後再使用這個變量。
函數聲明:
使用函數聲明
的形式建立的函數function foo(){}
,會被聲明提早。上面例四就是這個案例。
也就是說,整個函數會在全部的代碼執行以前就被建立完成。因此,在代碼順序裏,咱們能夠先調用函數,再定義函數。
代碼舉例:
fn1(); // 雖然 函數 fn1 的定義是在後面,可是由於被提早聲明瞭, 因此此處能夠調用函數
function fn1() {
console.log('我是函數 fn1');
}
複製代碼
函數表達式:
使用函數表達式
建立的函數var foo = function(){}
,不會被聲明提早,因此不能在聲明前調用。
很好理解,由於此時foo被聲明瞭(這裏只是變量聲明),且爲undefined,並無把 function(){}
賦值給 foo。
因此說,下面的例子,會報錯:
提醒1:在函數做用域中,也有聲明提早的特性:
函數中,使用var關鍵字聲明的變量,會在函數中全部的代碼執行以前被聲明。
函數中,沒有var聲明的變量都是全局變量,並且並不會提早聲明。
舉例:
var a = 1;
function foo() {
console.log(a);
a = 2; // 此處的a至關於window.a
}
foo();
console.log(a); //打印結果是2
複製代碼
上方代碼中,執行foo()後,函數裏面的打印結果是1
。若是去掉第一行代碼,執行foo()後,函數裏面的打印結果是Uncaught ReferenceError: a is not defined
。 a=2雖然是全局變量,可是不存在變量提高,不能前後聲明。
提醒2:定義形參就至關於在函數做用域中聲明瞭變量。
function fun6(e) { // 這個函數中,由於有了形參 e,此時就至關於在函數內部的第一行代碼裏,寫了 var e;
console.log(e);
}
fun6(); //打印結果爲 undefined
fun6(123);//打印結果爲123
複製代碼
在其餘編程語言中(如 Java、C#等),存在塊級做用域,由{}
包括起來。好比在 Java 語言中,if 語句裏建立的變量,只能在if語句內部使用:
if(true){
int num = 123;
system.out.print(num); // 123
}
system.out.print(num); // 報錯
複製代碼
可是,在 JS 中沒有塊級做用域(ES6以前)。舉例以下:
if(true){
var num = 123;
console.log(123); //123
}
console.log(123); //123(能夠正常打印)
複製代碼
引入:
只要是代碼,就至少有一個做用域
寫在函數內部的局部做用域
若是函數中還有函數,那麼在這個做用域中就又能夠誕生一個做用域
基於上面幾條內容,咱們能夠得出做用域鏈的概念。
做用域鏈:內部函數訪問外部函數的變量,採用的是鏈式查找的方式來決定取哪一個值,這種結構稱之爲做用域鏈。查找時,採用的是就近原則。
代碼舉例:
var num = 10;
function fn() {
// 外部函數
var num = 20;
function fun() {
// 內部函數
console.log(num);
}
fun();
}
fn();
複製代碼
打印結果:20。
關於更多做用域和做用域鏈的問題能夠看這篇文章,直接點我。
感謝閱讀,但願能對你有所幫助,文章如有錯誤或者侵權,能夠在評論區留言或在個人主頁添加公衆號聯繫我。
寫做不易,若是以爲不錯,能夠「點贊」+「評論」 謝謝支持❤