• ベストアンサー

配列に代入したエレメントを操作できない(変数のスコープの問題でしょうか?)

ページ上に複数のブロックを配置しています。ひとつにマウスオーバーすると枠の色が赤くなり、他のものの枠の色がグレーになるようにします。 以下にソースを記します。 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=euc-jp"> <title>array</title> <style type="text/css"> div { width: 50%; margin: 5px; padding: 5px; border: 3px solid #bbb; } </style> <script type="text/javascript"> <!-- var blockArr = new Array(); blockArr.push('First'); blockArr.push('Second'); blockArr.push('Third'); blockArr.push('Fourth'); blockArr.push('Fifth'); var blocks = new Array(); function init() { for (var i=0; i<blockArr.length; i++) { var theName = blockArr[i]; blocks[i] = document.getElementById('block' + theName); blocks[i].onmouseover = function() { for (var ii=0; ii<blockArr.length; ii++) { if (i==ii) { // nothing } else { blocks[ii].style.border = '3px solid #bbb'; } } blocks[i].style.border = '3px solid red'; // ←←← 変更箇所 }; } } window.onload = init; //--> </script> </head> <body> <div id="blockFirst">1</div> <div id="blockSecond">2</div> <div id="blockThird">3</div> <div id="blockFourth">4</div> <div id="blockFifth">5</div> </body> </html> FireFox2で表示したところ、これでは blocks[i] has no properties というエラーが出て動作しません。 試しに『// ←←← 変更箇所 』の行の宣言を『this.style.border = '3px solid red';』と this に変えてみたら動作しました。 しかしなぜ blocks[i] で動作しないのでしょうか。

質問者が選んだベストアンサー

  • ベストアンサー
  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

これは実行される順序と保持している値を勘違いしているためでしょう blocks[i]のiは ページがロードされたときに実行するinitの中で更新されます したがって initの終了時点では blockArr.lengthと同じの『5』になっています それに比べて iiはdivタグのマウスオーバーが発生した場合に更新されます mouseoverの無名関数の中で if ( i == ii ) と判定していますが iは常に5を保持していますので elseしか実行されないことになります blocks[i]をthisに変更して動作するのは mouseoverのイベントが起きたオブジェクトがthisだからです blocks[5]は存在しませんよね … blocksの添え字は0から4ですから

mataroh
質問者

お礼

回答ありがとうございます。 functionの中でvar宣言した変数が残らないのを、forループでも同様だと勘違いしておりました。 また、無名関数の中身というのは、記述された時点ではなく、イベントが発生した時点で定義されるということですね? このことは知りませんでした。たいへん参考になりました。

その他の回答 (1)

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.2

こんな感じでよいのでは? <html> <head> <style type="text/css"> div { width: 50%; margin: 5px; padding: 5px; border: 3px solid #bbb; } </style> <script type="text/javascript"> blockArr = ['First','Second','Third','Fourth','Fifth']; function init() { for (var i in blockArr){ var obj = document.getElementById('block' + blockArr[i]); obj.onmouseover = function() { for (var j in blockArr){ var obj = document.getElementById('block' + blockArr[j]); obj.style.border = '3px solid #bbb'; } this.style.border = '3px solid red'; } } } window.onload = init; </script> </head> <body> <div id="blockFirst">1</div> <div id="blockSecond">2</div> <div id="blockThird">3</div> <div id="blockFourth">4</div> <div id="blockFifth">5</div> </body> </html>

mataroh
質問者

お礼

回答ありがとうございました。 一度全てのブロックをグレーにしてからひとつを赤にするというやり方ですね。 こちらのほうがよりスマートなコードという印象を持ちました。他の方のやり方を拝見するのは参考になります。

関連するQ&A

専門家に質問してみよう