1、做用域(what?)前端
官方解釋是:「一段程序代碼中所用到的名字並不老是有效/可用的,而限定這個名字的可用性的代碼範圍就是這個名字的做用域。」
單從文字理解比較難懂,舉個栗子:
java
function outer(){ // 聲明變量 var name = "ukerxi"; // 定義內部函數 function inner() { console.log(name); // 能夠訪問到 name 變量 } } console.log(name); // 報錯,undefined
其中變量name聲明在 oute r函數中,當在 outer 中定義一個 inner 函數進行輸出 name,能夠獲得正確的值,而在 outer 外進行輸出 name 出現 undefined 錯誤;在此能夠看出 outer 函數即爲 name 變量的做用域(證實過程比較粗略,但結論仍是正確的--_--);編程
2、做用域(why?)後端
做用域的使用,提升了程序的邏輯的局部性,加強程序的可靠性,以及避免命名衝突;爲代碼的模塊化開發提供便利;根據上面提到的函數做用域,name 變量被侷限在了 outer 函數中,在其餘的函數中也能夠定義相同名字的變量,二者之間不會互相影響;瀏覽器
3、js 中的做用域app
先說ES5版本及更低版本的,由於在 ES6 上,從新定義了幾個決定做用域的關鍵字;模塊化
// C語言實現 for(int i= 0; i<10; i++){ // 中括號裏面就是塊級做用域 } if(ture){ int i = 1; // 這裏也是塊級做用域 } printf("%d/n",i); // --「use an undefined variable:i」 //這裏是訪問不到for語句中的i與if語句中的i變量的
for(var i= 0; i<10; i++){ // do something } console.log(i); // --10
function loop(){ for(var i= 0; i<10; i++){ // do something } } loop(); console.log(i); // --undefined
(function (){ for(var i= 0; i<10; i++){ // do something } }()); console.log(i); // --undefined
function range () { // let 和var 相同的地方,都有函數做用域 var name = 'ukerxi'; let nameOuter = 'outer'; for (var j = 0; j < 1; j++) { console.log(name) } console.log("輸出j變量", j); // ==> 1 for (let i = 0; i < 1; i++) { console.log(nameOuter) } console.log("輸出i變量", i); // 報錯 undefined }
能夠看出,使用let 定義的i變量,在for語句外進行輸出時,會進行報錯,說明i不在該做用域內,i的做用域在for包裹的做用內;函數
function fn(name){ var text = "test"; } // 變量對象中包含:命名函數fn變量、參數name、內部變量test
固然這個變量對象是不可訪問的,只提供後臺引擎編譯執行使用;當定義有多個變量對象嵌套,這些變量對象就組成了做用域鏈;例如:oop
var name = "global"; function super() { var name = "super"; function sub(){ var name = "sub"; } }
做用域鏈:
this
在做用域最前端的是活動對象,而最後端是全局執行環境window(瀏覽器宿主中);變量訪問原則是,根據做用域前端往上進行搜索,若是提早搜索到變量,則中止搜索,例如上面這個例子中,name變量的值是"sub"由於其在最前端的變量對象中已經定義了,就不會往上繼續檢索;
var name = "global"; function test(){ var name = "sub"; with(window){ console.log(name); } } test(); // -- "global"
做用域鏈:
因此檢索變量時,會先在最前端的window變量對象中檢索;固然,在嚴格模式下已經禁用了with語句,編程時,最好向後兼容,廢棄使用with語句;
var name = "global"; function getName(){ console.log(name); } function test (){ var name = "inner"; getName(); } // 執行test test(); // -- global
運行test 函數,其中test 函數執行的是 getName 進行輸出 name 變量,輸出的是全局變量的信息;即當 getName 定義時就已經肯定了本身的做用域及執行環境,於是不會由於執行位置的不一樣而輸出不一樣的信息;固然有一種狀況不同,那就是靈活的 this
// 聲明一個類 function Person (){ this.name = "ukerxi"; } // 使用new關鍵字,使this執行新建對象 // 實際上是構造函數默認返回this var men1 = new Person(); // this綁定到men1上 // 聲明一個空對象,使用call/apply 進行綁定 var men2 = {}; Person.call(men2); // this綁定到men2上 // 直接執行構造函數 Person(); // this綁定到window上(使用嚴格模式則會報錯,this指向undefined)
【結束語】
系列文章,包括了原創,翻譯,轉載等各種型的文章;一方面是爲了本身總結,另外一方面頁但願能夠共享知識;在技術方面有輸入,也要有所輸出,才能更進一步!文章基於本身的實踐、閱讀及理解,若有不合理及錯誤的地方,煩請各大佬評論指出,以便改正,感謝!