js 函數閉包=bug
阿新 • • 發佈:2019-05-08
執行 理解 object nbsp onclick 代碼執行 存在 銷毀 ret
1.錯誤理解
閉包就是個bug,閉包其實是利用了一個變量退出作用域的時候,暫時沒有被銷毀,它的值還在,如果後面有變量也叫這個名字,那這個數據會被重新利用起來。你會發現,後面你使用的這個名字一樣的變量是有初值的。下面的例子可以看出問題來。
<p>局部變量計數。</p>
<button type="button" onclick="myFunction()">計數!</button>
<p id="demo">0</p>
<script>
{
var tmp = 2; //理論上在退出語句塊後,這個變量要被釋放掉的。包括內存可能被回收。但事實並非如此,會影響後面和他同名的變量
}
var add = (function () {
//var counter = 0; //這裏註釋掉.其實和上面的tmp一樣的道理。這裏在函數自己執行完後就應該銷毀了的。
//return function () {return counter += 1;} //這裏的counter已經不是上面的counter了,是一個全局變量。有初值,受上面影響,初值為0
return function () {return tmp += 1;} //這裏tmp就是個全局變量。它是有初值的。為上面的2
})();
function myFunction(){
document.getElementById("demo").innerHTML = add();//3
document.getElementById("demo").innerHTML = add();//4
document.getElementById("demo").innerHTML = add(); //5
}
</script>
執行上面的代碼可以看的很清楚。計數器一樣正常工作。
所以,閉包就是利用了個bug: 退出作用域的變量不會立即銷毀。會影響後面的同名變量。
但不知道後面的javascript版本會不會修改這種機制。
所以代碼這麽寫是不可靠的。太依賴於javascript的內部實現了。
其實要實現全局計數器的需求。正常的做法是:
定義一個全局對象。這個對象定義自己的屬性和方法add。
用的時候 對象.add 就可以了。這個才正常。
上面用閉包的方式太過巧妙,給人的感覺就是在夾縫中求生存。用起來也不舒服吧。
這個 bug 用著真不痛快,針對這個例子寫了點代碼:
局部變量計數。
<button type="button" onclick="myFunction()">計數!</button>
<p id="demo">0</p>
<script>
var add = new Object();
add.count = 0;
add.plus = function()
{
this.count++;
}
function myFunction(){
add.plus();
document.getElementById("demo").innerHTML = add.count;
}
</script>
感覺可以用正常的手段解決這類問題了。
2.正解
{ var tmp = 2 } JS 中語句塊不能獨立作用域,這樣寫等同於聲明了一個全局變量 tmp = 2,所以不存在該語句塊內代碼執行完畢後 tmp 就被銷毀的情況。
變量 add,以及 add 的 count 屬性、plus() 方法都是公共的,這意味著其他代碼可以直接修改你的 count 屬性,造成不必要的麻煩
閉包要解決的問題是:一個函數可以擁有私有變量,並且外部可以通過閉包訪問該私有變量,如特權方法(類似 JavaBean 的寫法):
<script>
function Student(value) {
var name = value;
this.getName = function() { return name; };
this.setName = function(value) {name = value; };
}
<script>
js 函數閉包=bug