一、js中的詞法作用域和動態作用域
詞法作用域也就是在詞法階段定義的作用域,也就是說詞法作用域在代碼書寫時就已經確定了。
js中其實只有詞法作用域,並沒有動態作用域,this的執行機制讓作用域表現的像動態作用域,this的綁定是在代碼執行的時候確定的。
example1: 理解詞法作用域
記住js中只有詞法作用域沒有真正的動態作用域,作用域是在代碼書寫時確定的
var value = 1; function foo() { console.log(value); } function bar() { var value = 2; foo(); } bar();
//1
輸出是1,函數在哪里調用沒有關系,變量的位置在編譯的詞法分析階段就確定了。
當調用foo時,會對value進行一次RHS查詢,在當前函數作用域中沒有查找到會查找到最外層的作用域,也就是全局作用域定義的value。
二、修改詞法作用域
在代碼書寫時,作用域(詞法作用域)就已經確定了,但是可不可以再修改呢?
通過eval和with都可以用來修改詞法作用域。
eval:
function foo(str, a) { eval(str) console.log(a, b)//1,3 } var b = 2; foo("val b = 3", 1)
with:
用來重復引用同一個對象中的多個屬性的快捷方式
可以理解為修改對象中多個屬性的值的快捷方式
function foo(obj) { with(obj) { a = 7 } } var obj1 = { a: 2 } var obj2 = { b: 3 } foo(obj1) console.log(obj1)// {a=7} console.log(a) //7 foo(obj2) console.log(obj2)//{b:3} console.log(a)//7
with可以定義一個詞法作用域, 值得注意的是with中定義的a=2會在全局作用域中包含一個a變量。
三、函數作用域和塊作用域
1、創建作用域的方式
a)通過函數創建局部作用域
1、通過函數聲明的方式創建
2、通過函數表達式創建:
匿名函數表達式和具名函數表達式
區別函數表達式和函數聲明的方式就是看聲明的第一個關鍵字是否是function開頭
b)通過with、try...catch、let和const創建塊作用域
值得提的是let和const定義的塊作用域
let在聲明變量時,會將變量附加在一個已經存在的塊作用域上,一般是{}(隱式附加),let聲明的變量是在js運行的時候才存在的。