1. 程式人生 > >addEventListener和onclick

addEventListener和onclick

很高興有一個純JS的問題。
1,@楊咖啡 說的JS傳參是傳值不傳址,其實不是這樣的。JS中傳參有兩種方式:by value and by sharing.
像C,C++,Java,他們傳參方式是by value 和 by reference。前者就是傳值,後者是傳址。而JS也是這樣的,前者是傳值,後者是傳址。
By value是對於原始資料型別,例如int,char之類的;而By sharing 和By reference是對於高階資料結構,如Object,struct之類。我們可以想象到一個Object或是struct 不能僅僅通過傳值進行傳參。
一個簡單的例子說明by reference和 by sharing的不同。
var bar;
var foo = bar;
bar = {'key' : 'value'};
console.log(foo , bar );

By sharing 中foo 是undefined , bar 是{'key' : 'value'}; 而By reference 則應該兩者都是{'key' : 'value'}。

2. 其實LZ要理解這個問題,要明白JS中的作用域(scope)。
每個函式在建立完成時,他有3個重要的內建屬性(property)也同時被建立。
{
AO //記錄function內的變數,引數等資訊
this // 就是在呼叫this.xx的時候的this
scope // 指向外層函式AO的一個鏈(在實現的時候,可能通過陣列來實現).
}

JS中,大家經常講的Scope其實是這樣:SCOPE=AO+scope.
回到閉包的問題上:
如果我們這樣寫這個程式:
for(var i =0; i<link.length; i++){ //window scope
link[i].onclick = function(){ alert(i); }; // inner function
}

可以得到inner function的SCOPE是這樣的:

{
AO
this // 等於link[i]
scope // 指向window的記錄,包括我們需要的變數i
}
這個for迴圈會立即執行完畢,那麼當onclick觸發時,inner function查詢變數 i 時,會在AO+scope中找,AO中沒有,scope中的變數i已經成為了link.length.

利用大家所說的閉包寫這個程式:
//here is the window scope
for(var i =0; i<link.length; i++){

link[i].onclick = (function(i){ // outer function
return function(){ //inner function
alert(i);
};
})(i);
}
分析inner function的SCOPE:
{
AO // no important infomation
this // we don't care it.
scope //outer function and window scope
}
outer function的SCOPE
{
AO // 包含引數i
this // don't care it .
scope // window scope.
}


這時,如果inner function被觸發,他會從自己的AO以及scope(outer function的AO 和 window scope)中找尋變數i. 可以看到outer function的AO中已經包含了i,而且對於這個for迴圈,會有對應有N個(function(){})() 被建立執行。所以每個inner function都有一個特定的包含了變數 i 的outer function。

這樣就可以順利輸出0,1,2,3。。。。。。。。。

結論: 我們可以看到,閉包其實就是因為Scope產生的,所以,廣義上來講,所有函式都是閉包。


另外,這裡面也包含了,this, function expression 和function declaration的區別,這裡就不一一講了。

3. 另外一種方法:
利用 dom onclick事件的bubble特性,也就是@xiiiiiin所講的弄個代理。

在link dom節點的父節點上定義onclick事件監聽。引數為e(其他的名字也可以,但要有引數)。 這樣我們通過e.target就可以知道是那個子節點被click了,也可以做相應的處理。
這是一個比較好的方法。(閉包有時會產生記憶體洩漏)。