0

このコードは Chrome では完全に動作しますが、Firefox では関数tile1が定義されていないとのことです。何が問題なのですか?

また、この関数を短縮する方法はありますか? 内部で for ループtile1if-elseステートメントを使用しようとしましたが、成功しませんでした。

$('div.tile').each(function(index, element) {
  for(var i=0;i<=index;i++){

  var tile1=function(){
    var one ="div.tile div.one";
    var two =" div.tile div.two";
    var three = "div.tile div.three";
    if(index==0){
      one="div.tile div.one";
      two="div.tile div.two";
      three="div.tile div.three";
    } else {
      one ="div.tile div.one"+index;
      two ="div.tile div.two"+index;
      three ="div.tile div.three"+index;
    }
      var $one=$(one);
      var $two = $(two);
      var $three=$(three);
      var oneTop = $one.top;
      var twoTop = $two.top;
      var threeTop = $three.top;
      delayRate += 3000; // delayRate 5 sec (5000) by default 

     $one
       .delay(delayRate)
       .animate({top: "-100.5%"},300,easing);   
     $two
       .delay(delayRate)
       .animate({top:"0%"},300,easing);
     $three
       .delay(delayRate)
       .animate({top:"100.5%"},300,easing);     

     $one
       .delay(12000)
       .animate({top: "-200.5%"},300,easing);
     $two
       .delay(12000)
       .animate({top:"-100.5%"},300,easing);
     $three
       .delay(12000)
       .animate({top:"0"},300,easing);

     $one
       .delay(12000)
       .animate({top: "-100.5%"},300,easing);
     $two
       .delay(12000)
       .animate({top:"0"},300,easing);
     $three
       .delay(12000)
       .animate({top:"100.5%"},300,easing);

     $one
       .delay(15000-delayRate)
       .animate({top: "0"},300,easing);
     $two
       .delay(15000-delayRate)
       .animate({top:"100.5%"},300,easing);
     $three
       .delay(15000-delayRate)
       .animate({top:"200.5%"},300,easing);

     if(i==3){
       delayRate=0;
     }
   }
 }  
 window.setInterval(tile1, 3000);
});

関数を呼び出すと、index0、3、1、2 のようにランダムに来て、インデックスが対応する 4 つの div があります。

4

1 に答える 1

6

JavaScript で関数ステートメントを使用することはお勧めできません。関数スコープに関する Mozilla のページをチェックしてください。このページには、関数ステートメントと関数式に関する優れたセクションがあり、次のように述べられています。

関数は、 //function ステートメント // (ECMA-262 Edition 3 標準の許可された拡張機能) または Function コンストラクターを使用して、条件付きで定義できます。このような関数ステートメントは、ES5 strict では許可されなくなっていることに注意してください。さらに、この機能はクロスブラウザーで一貫して機能しないため、依存しないでください。

このコードを使用するブラウザー間で違いが見られるという事実は、驚くべきことではありません。

試す

var tile1 = function () {
    ...
}

varここではこれでうまくいくはずですが、変数定義が巻き上げられているためだけです。JavaScript が進化し、letの代わりに を使用し始めると、が定義されているループ外の呼び出しでをvar使用しても機能しなくなります。tile1setIntervaltile1

発生する可能性のある問題の 1 つはi、内部関数内で を使用する場合、常に外部スコープ (ループ カウンター) 内の の単一インスタンスを参照していることです。iその値は常に に等しくなりindexます。(編集:これを修正する方法を以下に示します。)

ループ内で関数を定義するときは、常に細心の注意を払ってください。クロージャーと巻き上げ、および関連する概念を本当に理解する必要があります。tile1ループの外でグローバルに定義できる方法はありますか?

コード構造の単純化に関するご質問については、で定義tile1しても問題ないと思いますが、 で内部ループを使用する必要はないと思います試す:vari

$('div.tile').each(function(index, element) {
  var tile1 = function () {
    var one ="div.tile div.one";
    .
    .
    .
    if (index === 3) {   // CHANGED I TO INDEX HERE.
      delayRate=0;
    }
  }
  window.setInterval(tile1, 3000);
});

内側のループが何を買っていたのかわかりません。

補足: 将来の JavaScript バージョンでは、ブロック スコープ内の関数ステートメントを処理するための作業が進行中です。これは Chrome の特定のバージョンではサポートされていますが、Firefox ではサポートされていないことがわかります。

補遺

tile1さて、関数で 3 つのステップを循環させたいことがわかりました。関数内に for ループを配置することは可能ですが、JavaScript の方法では、関数のアニメーションを毎回 1 ステップだけ実行します。ある種のカウンターが必要な場合、カウンターは外部にある必要があります。これを行う1つの方法は次のとおりです。

var tile1 = function (i) {
  .
  .
  // use the value i here as needed
  .
  .
  setTimeout(function () {tile1((i + 1) % 3)}, 3000);
};
tile1(0);

これが行うことは、最初に値 0 でタイル関数を呼び出すことです。次に、0 で必要なことを行った後、i = 1 で 3 秒後に次のフレームを実行するようにスケジュールします。次に、2 で 3 秒ほど後に実行します。 、その後 3 秒ほどで 0 になります。

ここには少しドリフトがあるので、 を使用することをお勧めしますsetInterval。これには閉鎖が必要です。ソリューションの形式は次のとおりです。

(function () {
  var i = 0;
  var tile1 = function () {
    .
    .
    // use the value i here as needed
    .
    .
    i = (i + 1) % 3;
  };
  setInterval(tile1, 3000);
}());

このコードはかなりクールです。これは、関数を 3 秒ごとに実行するようsetIntervalにスケジュールするために呼び出す無名関数の呼び出しです。tile1実行するたびに、クロージャーでコードの残りの部分から隠されてtile1いる非ローカルの値を使用します。iの各実行はtile1の正しい値を使用し、次の呼び出しのために適切な値にi変更して終了します!i

これらの手法はどちらも、JavaScript で習得するのに適しています。それらを楽しんでください。もちろん、2 番目のものにはクロック ドリフトがないため、おそらくより優れています。コードを専門化するために、変数に結果を割り当てて、後でsetInterval呼び出すことができます。clearInterval

于 2013-06-21T04:49:15.383 に答える