2016-03-14 7 views
6

私は本のJqueryのいくつかの例をjavascriptにリファクタリングしてjavascriptを学んでいます。次のコードでは、クリックリスナーをタブに追加し、ユーザーがタブをクリックしたときにクリックリスナーをアクティブに変更します。私のjavascriptコードでは "これ"を理解しようとしています(あるものは動作し、もう一方は動作しません)

var tabs = document.querySelectorAll(".tabs a span"); 
 
var content = document.querySelectorAll("main .content li"); 
 

 
for (var tabNumber = 0; tabNumber <= 2; tabNumber++) { 
 
    tabs[tabNumber].addEventListener("click", function (event) { 
 
    
 
    for (var i = 0; i < tabs.length; i++) { 
 
     tabs[i].classList.remove("active"); 
 
    } 
 
    tabs[tabNumber].classList.add("active"); 
 
    for (var i = 0; i < content.length; i++) { 
 
     content[i].innerHTML = ""; 
 
    } 
 
    event.preventDefault(); 
 
    }); 
 
}

私はそれを実行したときにこれがundefined errorを返します。しかし、tabs[tabNumber].classList.add("active")this.classList.add("active")に置き換えてみました。

なぜ前のコードは機能しませんか?私が見る限り、彼らは同じことを指しており、はコードのその時点でそれがtabs[0]であるので動作するはずです。

+3

イベントハンドラ内でconsole.log(tabNumber)を使用した場合、クリックしたアイテムに関係なく3であることがわかります。 – nnnnnn

+0

forループを可能な限り使うように 'let'を使いますが、クロージャやJSコードで参照する場所で問題を解決できます。 – Gary

答えて

3

tabs[tabNumber]がなぜ機能しないのか(なぜならそれはforループのスコアから来ているので、常にtabNumberの大きな値に等しいので)他の答えがあなたに語ったと思います。

だから、.forEachループを使用することをお勧めします。それはdocument.querySelectorAll()によって生成DOMノードの配列では動作しませんが、あなたが使用することができますので、しかし慎重に:

// ES6 
Array.from(document.querySelectorAll('...')) 
// ES5 
[].slice.call(document.querySelectorAll('...')) 

をとにかく、私はあなたのコードの簡略化working demoを作りました。 別のforループを防ぐために、現在アクティブなタブを変数に保存しています。あなたもできる:

document.querySelector('.active').classList.remove('active') 

しかし、私はDOMの読みの量を減らすのが好きです。

あなたの勉強に恵まれて、バニラJSにjQueryコードを書き直すのは良い方法のように思えますし、JavaScriptをもっとよく理解するかもしれません。

4

thisを使用している場合は、より優れた洗練されたソリューションだと思います。 tabNumberをまだ使用したい場合は、クリックコールバックごとに3と評価される可能性があります。これは、最後の反復後の数値であり、tabs[3]の位置がないためです。

したがって、変数tabNumberのクロージャを作成するだけで済みます。