函數作用域, 塊級作用域和詞法作用域
0 作用域:
0.1 作用域是程序源代碼中定義變量的區域。
0.2 作用域規定了如何查找變量,也就是確定當前執行代碼對變量的訪問權限。
0.3 ECMAScript6之前只有全局作用域和函數作用域。
0.4 JavaScript采用詞法作用域(lexical scoping),也就是靜態作用域。
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f();
}
checkscope(); //local scope
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
checkscope()();//local scope
1 變量作用域:全局變量和局部變量
var a=1; //全局變量
function B(){
alert(a);
}
function B(){
var c=1; //局部變量
alert(c);
}
function C(){
d=1; //全局變量
alert(d);
}
d;//1
2 閉包:就是能夠讀取其他函數內部變量的函數。由於在Javascript語言中,只有函數內部的子函數才能讀取局部變量,因此可以把閉包簡單理解成"定義在一個函數內部的函數"。所以,在本質上,閉包就是將函數內部和函數外部連接起來的一座橋梁。
2.1 用途:以讀取函數內部的變量;讓這些變量的值始終保持在內存中。
function f1(){
var count=6;
add=function(){
count+=1;
}
function f2(){
console.log(count);
}
return f2;
}
var f=f1();
f();//6
add();
f();//7
原因就在於f1是f2的父函數,而f2被賦給了一個全局變量,這導致f2始終在內存中,而f2的存在依賴於f1,因此f1也始終在內存中,不會在調用結束后,被垃圾回收機制(garbage collection)回收
2.2 注意點:
2.2.1 由於閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。
2.2.2 閉包會在父函數外部,改變父函數內部變量的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變量的值。
3 詞法作用域
3.1 一般來說,在編程語言里我們常見的變量作用域就是詞法作用域與動態作用域(Dynamic Scope),絕大部分的編程語言都是使用的詞法作用域。詞法作用域注重的是所謂的Write-Time,即編程時的上下文,而動態作用域以及常見的this的用法,都是Run-Time,即運行時上下文。詞法作用域關注的是函數在何處被定義,而動態作用域關注的是函數在何處被調用。JavaScript是典型的詞法作用域的語言,即一個符號參照到語境中符號名字出現的地方,局部變量缺省有着詞法作用域。
function foo() {
console.log( a ); // 2 in Lexical Scope ,But 3 in Dynamic Scope
}
function bar() {
var a = 3;
foo();
}
var a = 2;
bar();