最近在讀大叔譯的javascript編程精解這本書,確實是本好書,大愛。
以前對javascript某些概念迷迷糊糊,雖然知道怎么回事,但一直弄不明白其中的原因...
那么就先拿以前一直弄不明白的這道題講講吧,如下:
例1:
< a href ="javascript:;" >點我 </ a > /
< a href ="javascript:;" >點我 </ a >
< script type ="text/javascript" >
var atags = document.getElementsByTagName( ' a ' );
for ( var i = 0 , max = atags.length; i < max; i ++ ) {
atags[i].onclick = function () {
alert(i);
}
}
</ script >
預期結果可能是想彈出 0,1,2。可惜的是都彈出了:3
如果你一搜,一般會有這樣的解決辦法,如下面:
例2:
var atags = document.getElementsByTagName( ' a ' );
for ( var i = 0 , max = atags.length; i < max; i ++ ) {
( function (index) {
atags[i].onclick = function () {
alert(index);
}
})(i);
}
</ script >
分析下兩個例子的運行情況,首先了解一下javascript的幾個知識點:
1、作用域
2、閉包
3、自執行函數。
4、值類型和引用類型
我來引用一下最近讀這本書的幾句精解:
1、JavaScript唯一能創建新作用域的地方是 function
2、包裹一些局部變量的一個函數叫做一個閉包
3、自執行函數表達式這個大家應該都很清楚了,不清楚就去看下大叔的:即調用的函數表達式
4、這個也應該清楚吧,我說下吧:Number Boolean String 在 js 里屬於值類型,對像屬於引用類型,如下例:
function changeValue(value) {
value = 5 ;
}
function changeObj(objValue) {
objValue.i = 5 ;
}
var i = 0 ;
var obj = { i: 0 };
changeValue(i);
changeObj(obj);
alert(i); // 0
alert(obj.i); // 5
</ script >
到這里,上面的幾個知識點,應該都比較清楚了。
先來看作用域:JavaScript唯一能創建新作用域的地方是 function,那么就是說像 for 這類的是不會產生自己的作用域的。我們來實驗一下。
//這里干點啥
}
alert(i); //5
可以看出,for里的定義確實不會產生自己的作用域,這個其實也就是在全局里定義了一個變量i,就像以下這樣:
for (; i < 5 ; i++) {
}
alert(i); //5
貼心提示:從上面的例子我們能看出,一定要理解作用域,否則很容易發生沖突。比如:
var i = 9527;
//b某在這寫了這貨
for (var i = 0; i < 5 ; i++) {
//
}
//a某在這果斷悲劇了。
alert(i);
那么我們再來看上面的例1,這時我們應該很清楚為什么會全部彈出:3了。
因為所有鏈接彈出的是全局變量i,而全局變量i在循環完后的值是3,如下:
var atags = document.getElementsByTagName( ' a ' );
for ( var i = 0 , max = atags.length; i < max; i ++ ) {
atags[i].onclick = function () {
alert(i);
}
}
alert(i); // 這里顯示:3
</ script >
例2:這里如果理解上面的一些知識,例2也就不難理解了。
匿名自執行函數表達式收到index,因為是值類型參數,所以匿名函數內部重新分配這個局部變量。
然后鏈接 onclick 綁定的那個事件函數就是匿名函數的內部函數,並引用了匿名函數的那個局部變量(index)(這里是產生了一個閉包的)
最后的結果就是三個鏈接分別顯示了三個匿名函數的局部變量。
[注:這里感謝 @Justany_WhiteSnow 的指點,原先我認為例2沒有產生閉包,我說錯了,差點誤導大家,這里及時做個修改吧。並且把 @Justany_WhiteSnow 的正確見解在這里與大家分享下。]
另外我們還可以把那個自執行函數拿到外面:
function bind(index) {
atags[index].onclick = function () {
alert(index);
}
}
var atags = document.getElementsByTagName( ' a ' );
for ( var i = 0 , max = atags.length; i < max; i ++ ) {
bind(i);
}
</ script >
好,這篇就到這了,有什么說錯的地方歡迎大家指正。
轉載請注明出處,謝謝。