幾乎全部的編程語言都有做用域的概念,並且理解該門語言做用域是掌握這門語言的必經之路。若是你要訪問某個變量或函數,做用域則決定了你可否訪問到,換句話說做用域控制着變量與函數的可見性和生命週期。javascript
記得剛剛學js的時候(其實當時壓根沒怎麼學js,按照對Java的理解就直接開始用了),對於js的做用域這塊徹底是按照Java的做用域來理解的,結果就這樣寫點簡單的js倒也沒有太大的問題,可是後來業務愈來愈複雜,須要寫的js也愈來愈複雜,就發現js的做用域和Java的不同呢!(對於Java和JavaScript之間的關係還有疑問的同窗,只須要記住這兩種語言的共同點就是名字都含有Java就是了。)那麼js的做用域是怎麼的樣呢?下面咱們就說道說道。html
在js裏面,以函數來分隔做用域,又稱函數做用域: 做用域在函數內修改。 如:java
function scopeFunc(){ for(var i=0;i<5;i++){ //console.log(i); } console.log(i); } scopeFunc();//5 //若是js有塊級做用域,那麼在for循環外應該是取不到i的值的,應該報錯,可是咱們照樣取到了i的值;這裏的i是局部變量 function scopeFunc2(){ for(let i=0;i<5;i++){ //console.log(i); } console.log(i); } scopeFunc2();//i is not defined //在ES6(ES2015)以前,咱們看到js是沒有塊級做用域的,可是ES6新有的定義變量的let關鍵字,能夠定義塊級做用域 function Student(name){ console.log(name);//ly var score; console.log(score);//undefined console.log(age);//ReferenceError: age is not defined } Student('ly'); console.log(name);//undefined;函數參數只在函數內起做用,是局部變量。 //咱們看到在函數內使用一個定義了可是未賦值的變量的時候,提示undefined,使用一個未定義的變量時提示出錯了。 //scopeFunc是函數的句柄,在js中,對象和函數一樣也是變量,此處,scopeFunc是全局函數,也是全局變量了 setTimeout(scopeFunc,500); //setTimeout這裏用的是函數的句柄,若是寫成setTimeout(scopeFunc(),500);會形成內存泄露 /* 最外層函數和在最外層函數外面定義的變量擁有全局做用域,因此聲明全局變量比較簡單,不過有種特殊的狀況,在函數內, 若是不使用var聲明,直接給變量賦值,這個變量直接就擁有全局做用域 */ function wholeScopeFn(){ testw='imwhole';//若是不使用var聲明變量,此處就至關因而window.testw='imwhole'; var testpart='impart'; console.log(testpart); } console.log(testw);//ReferenceError: testw is not defined wholeScopeFn();//impart console.log(testw);//imwhole /* 全局變量咱們均可以經過window.變量名 的方式來獲取,可是當使用var聲明一個全局變量時, 建立的這個屬性是不可配置的,也就是說沒法經過delete運算符刪除,不使用var聲明的全局變量,能夠經過delete刪除 */ //函數運行在它們被定義的做用域裏,而不是它們被執行的做用域裏 function Student(name){ console.log(name);//ly var score; console.log(score);//undefined console.log(age);//ReferenceError: age is not defined } function myCare(){ var age=10; Student('ly'); } myCare(); //咱們看到,myCare函數內已經聲明並初始化了一個變量age,而在Student函數內,在執行到打印age變量的時候任然提示爲定義
總結一下就是變量在函數外定義,就是全局變量。 變量在函數內聲明,就是局部變量, 只能在函數內部訪問。編程
說了變量的做用範圍,還得說說變量的生命週期。生命週期意味着你用了當前變量以後下次用的時候他得是個什麼。簡單的說,變量在他還能被用到的時候就不會被銷燬,不能再被用到的時候就該銷燬了,生命也就走到盡頭了。如:編程語言
function scopeLife(){ var sl=0; console.log(++sl); } var wsl=0; scopeLife();//1 scopeLife();//1 scopeLife();//1 ;局部變量在函數執行完畢後銷燬。 console.log(++wsl);//1 console.log(++wsl);//2 console.log(++wsl);//3 ;全局變量在頁面關閉後銷燬。
好的,咱們再來看看和做用域有關的一個有趣的地方,變量聲明提高。函數
var name='ly'; function Student(){ console.log(name);//undefined var name='liuyong'; console.log(name);//liuyong } //上面的代碼能夠寫成以下 var name='ly'; function Student(){ var name; console.log(name);//undefined name='liuyong'; console.log(name);//liuyong } //這樣是否是好理解得多了,當執行函數的時候,會先函數內的變量的聲明。 //若是函數內不寫var直接定義全局變量,這樣的變量是不會被提高的 function Student(){ console.log(name); name='liuyong'; console.log(name);//liuyong } Student();
說到js做用域,若是不說做用域鏈,會不會顯得過低端了呢?哈哈,能夠看下這兩篇文章(JavaScript做用域鏈詳細介紹,JavaScript 開發進階:理解 JavaScript 做用域和做用域鏈),我的以爲做用域鏈這塊,這兩篇文章講得挺不錯的。有什麼問題也歡迎交流。spa