請教一個js問題,為什麼報錯?

菜鳥求告知js中下面這一小段報錯是哪裡有問題

var aaa=document.getElementsByTagName("img");

for(j = 0; j&< aaa.length ; j++){

aaa[j].onclick = function(){

aaa[j].style.boxShadow= "5px 5px 5px #000000";

aaa[j].style.margin = "0px 10px 10px 0px";

}

}

錯誤提示Cannot read property "style" of undefined


在題主的代碼中,aaa[j].onclick定義了一個函數,這個函數中可以訪問外部變數j,這就構成了一個閉包。當點擊事件被觸發時,調用了 該函數,這時【】會為該函數創建一個執行環境,構建起它的作用域鏈,此時早已定義完點擊事件函數了,j已經等於aaa.length,這時執行了aaa[aaa.length]便會報錯啦。

那怎麼辦呢?怎麼讓執行時的j的值還是創建時的j的值呢?

解決方案有三個:

1.onclick的function中,換成this.style....

var aaa=document.getElementsByTagName("img");
for(j = 0; j&< aaa.length ; j++){ aaa[j].onclick = function(){ this.style.boxShadow= "5px 5px 5px #000000"; this.style.margin = "0px 10px 10px 0px"; } }

原理:

this對象是在運行時基於函數的執行環境綁定的,當函數被作為某個對象的方法調用時,this等於那個對象。(javascript高級程序設計第三版182頁)。也就是說這時候this就是被點擊的那個節點對象啦,就會執行正確的行為。

2.把j作為參數傳進去

var aaa=document.getElementsByTagName("img");
for(j = 0; j&< aaa.length ; j++){ var loop = function(j){ aaa[j].onclick = function(){ aaa[j].style.boxShadow= "5px 5px 5px #000000"; aaa[j].style.margin = "0px 10px 10px 0px"; } }(j) }

原理:

我們把j作為值傳遞給一個匿名函數的參數j。每個匿名函數會被立即執行,而每個點擊事件的函數作為一個閉包,可以訪問到它們各自外面對應的匿名函數中的j,所以這時j的值是符合預期的。

3.使用let塊級作用域

var aaa=document.getElementsByTagName("img");
for(let j = 0; j&< aaa.length ; j++){ aaa[j].onclick = function(){ aaa[j].style.boxShadow= "5px 5px 5px #000000"; aaa[j].style.margin = "0px 10px 10px 0px"; } }

加一個let就好啦,我猜想是因為let創建的變數是塊級作用域變數,裡面的點擊事件函數就像在調用函數內部的變數一樣,在函數被創建時就決定了它的值(而不是像外部變數一樣保存的是它的引用,在被執行時才得到)

題主可以看下js高程p178-183加深了解

如有不對請多指教


閉包呀!在函數內部還用aaa[j]去訪問外部的j,這裡就形成了一個閉包,所以相當於你指定了n次aaa[length]的點擊事件,而根本不存在aaa[length]這個元素,所以報錯。

函數內部改為this吧,最簡單的改法。另外別的答案提到的類數組改成真數組,沒啥必要,有裝逼成分,太多此一舉。按照他的做法,那jQuery的選擇器還用不用了?也是個類數組哦。


你aaa[j].onclick=function(){} 就只是傳了個匿名函數

onlick的時候那個函數才執行

那個時候for早執行完了。

把匿名函數里的aaa[j] 改成this就好了


當你點擊click時,j==a.length,aaa[j]就==undefined,所以就報你那個錯誤了。你裡面可以使用this.style.XXX=XXXX來替換aaa[j].style.XXX=XXX;估計就好了


送分題。

答到變數作用域加分

答到閉包加分

答到es6的塊作用域和let聲明加分


首先,解決方法如下:

"use strict";

var aaa = document.getElementsByTagName("img");

var _loop = function _loop(j) {
aaa[j].onclick = function () {
aaa[j].style.boxShadow = "5px 5px 5px #000000";
aaa[j].style.margin = "0px 10px 10px 0px";
};
};

for (var j = 0; j &< aaa.length; j++) { _loop(j); }

其次,出現這樣的原因是for循環的時候後一次的j會覆蓋前一次的值,所以會直接賦值到最後,這裡你可以console.log(j);值應該是 aaa.length。望採納


click裡面的回調函數在觸發的時候,j=aaa.length,此時的aaa[j]是未定義的。

要解決這個問題需要用閉包,具體可參考這個鏈接 [Javascript實驗課]循環中的閉包


1.先看你的循環問題,如果你有兩張圖,最後的j是取值2,數組下標為2,實際取值為3,數組是從0開始計算的,aaa[2]代表第三張圖片,你壓根沒有,當然報錯。

2.上面一堆人答閉包的,我就不說了,可以參考變數作用域,和詞法環境記錄。


事件處理函數是非同步執行的,這意味著事件觸發(函數被調用)之前,for 循環已結束;函數調用時,其執行環境中 j 的值為 aaa.length, aaa[aaa.length] 的值為 undefined。


aaa[j].onclick = function(){

aaa[j] -----&> 這個j 在function 裡面的時候 已經是 img.length +1 了。

}

所以 你想 aaa[img.length +1] 不能有這個節點啦。其實就是閉包的問題

要是想直接想要結果 ,你把var j = 0 編程 let j = 0 就好了


這是你的demo

JS Bin - Collaborative JavaScript Debugging

點擊每一個img都會顯示j=aaa.length,找不到aaa[aaa.length]這個元素,所以會輸出cannot read property style of undefined

其他大神已經給出了解決方法了~你可以採用一個~


for(j = 0; j&< aaa.length ; j++){ aaa[j].onclick = function(){ console.log(j); console.log(j === aaa.length); aaa[j].style.boxShadow= "5px 5px 5px #000000"; aaa[j].style.margin = "0px 10px 10px 0px"; } }

你會發現每次console.log的時候,j 都是一樣的,並且 j === aaa.length

搜索下 「javascript 閉包 陷阱」 可以得到相關答案


非同步問題,你在onclick外面輸出下i就知道問題在哪了,手機答。。匿了


假設 答主 aaa.length =3 則 運算過程是這樣的

j=0時 aaa[0].onclick=function() {aaa[j].style.boxShadow= "5px 5px 5px #000000";

aaa[j].style.margin = "0px 10px 10px 0px";}

j++;

j=1時 aaa[1].onclick=function() {aaa[j].style.boxShadow= "5px 5px 5px #000000";

aaa[j].style.margin = "0px 10px 10px 0px";}

j++;

j=2時 aaa[2].onclick=function() {aaa[j].style.boxShadow= "5px 5px 5px #000000";

aaa[j].style.margin = "0px 10px 10px 0px";}

j++;

這時j=3

不管aaa[0]、aaa[1]還是aaa[3]發生點擊事件時 都會調用

onclick(){

aaa[3].style.boxShadow=

"5px 5px 5px #000000";

aaa[3].style.margin =

"0px 10px 10px 0px";}

而aaa[3]卻根本沒有定義 這就是錯誤之處。

建議題主,在尋找原因時,不妨在js代碼中寫個debugger斷點,進行調試一下。


用this就好了


推薦閱讀:

24歲從零開始學html晚不晚?
前端怎麼學才有優勢?
Html5標準下的footer置底的問題,為何min-height會失效?
有哪些網站的前端代碼風格非常好,值得學習?

TAG:HTML | CSS | JavaScript |