一、 JS中的作用域 |
1、全局變量:函數外聲明的變量,稱為全部變量
局部變量:函數內部使用var聲明的變量,稱為局部變量
在JS中,只有函數作用域,沒有塊級作用域!!!也就是說,if/for等有{}的結構體,並不能具備自己的作用域。
所以,函數外部不能訪問函數內部局部變量(私有屬性)。因為,函數內部的變量,在函數執行完畢以后,就會被釋放掉
2、使用閉包,可以訪問函數的私有變量!
JS中,提供了一種“閉包”的概念:在函數內部,定義一個子函數,子函數可以訪問父函數的私有便利。可以在子函數中進行操作,最后將子函數通過return返回
function func1(){ var num = 1; function func2(){ return num; } return func2; } var num = func1()(); console.log(num);
3、閉包的作用:
①可以在函數外部訪問函數的私有變量
②讓函數內部的變量可以始終存在於內存中,不會再函數調用完成后立即釋放。
function func1(){ var num = 1; function func2(){ return num; } return func2; } var num = func1()(); console.log(num);
結果為1
二、 全局變量的問題 |
【錯誤原因!!】
代碼從上自下,執行完畢后,li的onclick還沒有觸發,for循環已經轉完!
而for循環沒有自己的作用域!所以循環5次,用的是同一個全局變量i!也就是在for循環轉完后,這個全局變量已經變成了5,那么在怎點li,點第幾個都會是5
var lis = document.getElementsByTagName("li"); for(var i=0; i<lis.length;i++){ lis[i].onclick = function(){ alert(i); } }
有三種辦法解決上述問題:
1、【使用閉包解決上述問題】
解決關鍵:函數具有自己的作用域!!在for循環轉一次,創建一個自執行函數。在美國自執行函數中,都有自己獨立的i,而不會被釋放掉。
所以for循環轉完以后,創建的5個自執行函數的作用域中,分別儲存了5個不同的i變量,也就解決了問題
var lis = document.getElementsByTagName("li"); for(var i=0; i<lis.length;i++){ !function(i){ lis[i].onclick = function(){ alert(i); } }(i); }
2、【使用let解決】
解決原理:let具有自己的塊級作用域,所以for循環轉一次,創建一個塊級作用域,思路與閉包相同
var lis = document.getElementsByTagName("li"); for(let i=0; i<lis.length;i++){ lis[i].onclick = function(){ alert(i); } }
3、【使用this解決】
解決原理:出錯的原則在於全局變量i在多次循環后被污染。那么在點擊事件中,就可以不使用i變量,而用this代替lis[i],這樣也就不會出現錯誤!
var lis = document.getElementsByTagName("li"); for(var i=0;i<lis.length;i++){ lis[i].onclick = function(){ console.log(this) } }