做用域:編程語言最基本的功能就是存儲和訪問變量的值,如何對變量存儲/訪問的某種良好的規則,就是做用域。做用域負責收集並維護由全部聲明的標示符(變量)組成的一系列查詢,並實施一套很是嚴格的規則,肯定當前執行的代碼對這些標識符的訪問權限。es6
做用域是根據名稱查找變量的一套規則。當一個塊或者函數嵌套在另一個塊或者函數中時,就發生了做用域嵌套。編程
詞法做用域:定義在詞法階段的做用域。詞法做用域是你在寫代碼時將變量和塊做用域寫在哪裏來決定的,所以詞法分析器處理代碼時保持做用域不變。bash
函數做用域:每聲明一個函數都會爲自身建立一個做用域,屬於這個函數的所有變量均可以在這個函數範圍內使用/複用。一段代碼咱們能夠在它的外部添加一個包裝函數,這樣就能夠將內部的變量和函數定義隱藏(這種方法能夠有效解決變量或者函數污染外部做用域,閉包和函數自調用也是這種方法的延伸)。外部做用域沒法訪問包裝函數內部的任何內容。閉包
es5及以前只有函數做用域和全局做用域同時也只有兩種變量聲明,var 和function。 使用函數及變量的聲明都將被提高到當前做用域的最頂部。編程語言
1.變量提高(var的起做用,只有聲明提高,初始化不會):
var a =3;
function b( ) {
//實際上var了的變量提高到了函數內部的頂部
console.log( a );
var a=4;
}
b( ); // undefind
實際執行
var a =3;
function b( ) {
var a ; //var a 聲明!提高到此,並值爲undefined
console.log( a );
a=4; // 初始化
}
b();
2.函數提高(函數聲明起做用):
函數提高是把整個函數都提到前面去。
function f( ) {
console.log('I am outside!');
}
( function ( ) {
if ( false ) {
// 重複聲明一次函數f
function f( ) {
console.log( 'I am inside!' );
}
}
f( );
}( ) );//輸出'I am inside!'
實際執行:
function f( ) { console.log( 'I am outside!' ); }
( function ( ) {
function f( ) { console.log( 'I am inside!' ); }
if ( false ) {
// 重複聲明一次函數f
}
f( );
}( ) );
3.全局做用域的會被後面提高上來的覆蓋( var的變量爲undefined ), 局部做用域的會提高到函數內部的頂部;變量只有var的會提高,函數只有函數聲明會提高;
4:函數聲明和函數表達式
function a( ){ } //函數聲明 會提高
因此 :
a( );
function a ( ){ } //正確
var b = function ( ) { } //函數表達式 不會提高
因此:
b( );
var b = function ( ) { } //錯誤
複製代碼
es6引入了塊級做用域,並新增了四種聲明let/const/import/class。ide
1.// 只在當前做用域內能夠訪問
{
let a = 10;
var b = 1;
}
b // 1
a // ReferenceError: a is not defined.
2.// 同一做用域裏不容許重複聲明
let a = 'aaa';
let a = 'bbb'; //報錯 :語法錯誤
let a = 'aaa';
{let a = 'bbb';} // 不會報錯
3.// 不會變量提高
console.log(a); // 報錯
let a;
4.//暫時性死區 TDZ
var a =1;
{
let a = 3;
}
// 報錯 :引用錯誤
5.//全局聲明不會賦值到window對象
window.d = 123
let d = 234
console.log(d); // 234
2.let/const/import/class也遵照上述規則。
3.const是常量,不可再次被賦值(只限於棧內存裏數據,棧內存放的基本數據類型和引用類型的地址不可變)
複製代碼
1.let
for(let i =0; i<10; i++){
let i = 123;
setTimeout(
()=>{console.log(i);},
1000);
}
// 30786
// 123
console.log(i) // ReferenceError: i is not defined
for(var i =0; i<10; i++){
setTimeout(
()=> {console.log(i);},
1000);
}
// 51
// 10
for(let i =0; i<10; i++){
setTimeout(
()=> {console.log(i);},
1000);
}
// 0 1 2 3 4 5 6 7 8 9
2.const
const 在for循環中循環一次後會報錯,由於i++會修改值;
在for in 和for of中則能夠正常使用,由於每次循環會建立一個常量。
// 51
// 10
複製代碼