關於作用域、防止作用域汙染、作用域鏈和閉包的理解
作用域
變數的作用域無非就是兩種:全域性作用域和區域性作用域。 全域性作用域: 最外層函式定義的變數擁有全域性作用域,即對任何內部函式來說,都是可以訪問的:
<script>
var outerVar = "outer";
function fn(){
console.log(outerVar);
}
fn();//result:outer
</script>
區域性作用域: 和全域性作用域相反,區域性作用域一般只在固定的程式碼片段內可訪問到,而對於函式外部是無法訪問的,最常見的例如函式內部
<script>
function fn(){
var innerVar = "inner";
}
fn();
console.log(innerVar);// ReferenceError: innerVar is not defined
</script>
需要注意的是,函式內部宣告變數的時候,一定要使用var命令。如果不用的話,實際上聲明瞭一個全域性變數!
以下是一個重要的特性!!
只要函式內定義了一個區域性變數,函式在解析的時候都會將這個變數“提前宣告”,舉例:
<script> var scope = "global"; function fn(){ console.log(scope);//result:undefined var scope = "local"; console.log(scope);//result:local; } fn(); </script>
第一個輸出居然是undefined,原本以為它會訪問外部的全域性變數(scope=”global”),但是並沒有。這可以算是javascript的一個特點,只要函式內定義了一個區域性變數,函式在解析的時候都會將這個變數“提前宣告”。
<script> var scope = "global"; function fn(){ var scope;//提前聲明瞭區域性變數 console.log(scope);//result:undefined scope = "local"; console.log(scope);//result:local; } fn(); </script>
但是javascript不同,並沒有所謂的塊級作用域,javascript的作用域是相對函式而言的,可以稱為函式作用域:
<script>
for(var i = 1; i < 10; i++){
//coding
}
console.log(i); //10
</script>
防止作用域汙染
在多人協作時,如果定義過多的全域性變數 有可能造成全域性變數衝突,也就是全域性變數汙染問題, 儘量避免全域性變數。
可採取兩種措施:
一是定義全域性變數名稱空間,只建立一個全域性變數,並定義該變數為當前應用容器,把其他全域性變數追加在該名稱空間下
var MY={};
my.name={
big_name:"zhangsan",
small_name:"lisi"
};
my.work={
school_work:"study",
family_work:"we are"
};
二 是利用匿名函式將指令碼包裹起來
(function(){
var exp={};
var name="aa";
exp.method=function(){
return name;
};
window.ex=exp;
})();
作用域鏈(Scope Chain)
那什麼是作用域鏈? 我的理解就是,根據在內部函式可以訪問外部函式變數的這種機制,用鏈式查詢決定哪些資料能被內部函式訪問。 想要知道js怎麼鏈式查詢,就得先了解js的執行環境
執行環境(execution context)
js為每一個執行環境關聯了一個變數物件。環境中定義的所有變數和函式都儲存在這個物件中。
js的執行順序是根據函式的呼叫來決定的,當一個函式被呼叫時,該函式環境的變數物件就被壓入一個環境棧中。而在函式執行之後,棧將該函式的變數物件彈出,把控制權交給之前的執行環境變數物件。
<script>
var scope = "global";
function fn1(){
return scope;
}
function fn2(){
return scope;
}
fn1();
fn2();
</script>
上面程式碼執行情況演示:
閉包
閉包有兩個作用: 第一個就是可以讀取自身函式外部的變數(沿著作用域鏈尋找) 第二個就是讓這些外部變數始終儲存在記憶體中 (容易導致記憶體洩漏)
關於this物件
關於閉包經常會看到這麼一道題:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());//result:The Window
《javascript高階程式設計》一書給出的解釋是:
this物件是在執行時基於函式的執行環境繫結的:在全域性函式中,this等於window,而當函式被作為某個物件呼叫時,this等於那個物件。不過,匿名函式具有全域性性,因此this物件同常指向window。