2

以前JavaScriptで要素をフェードする方法を探していたところ、この関数(オブジェクト)に出会いました。私はそれがどのように機能するのか疑問に思い始めました。

var fadeEffect=function(){
return{
    init:function(id, flag, target){
        this.elem = document.getElementById(id);
        clearInterval(this.elem.si);
        this.target = target ? target : flag ? 100 : 0;
        this.flag = flag || -1;
        this.alpha = this.elem.style.opacity ? parseFloat(this.elem.style.opacity) * 100 : 0;
        this.si = setInterval(function(){fadeEffect.tween()}, 20);
    },
    tween:function(){
        if(this.alpha == this.target){
            clearInterval(this.elem.si);
        }else{
            var value = Math.round(this.alpha + ((this.target - this.alpha) * .05)) + (1 * this.flag);
            this.elem.style.opacity = value / 100;
            this.elem.style.filter = 'alpha(opacity=' + value + ')';
            this.alpha = value
        }
    }
}
}();

これは自己呼び出しであり、2 つのメソッドを持つ 1 つのオブジェクトのみを返すことがわかっています。私の主な関心事は、なぜ this キーワードを使用するのですか? 「this」キーワードは、オブジェクト名「fadeEffect」のプレースホルダーであると想定しています。「this」が複数のオブジェクトを作成するために使用された場合は理解できますが、なぜここで使用されているのですか?

私を悩ませているもう1つのことは、この三項演算子です...

   this.target = target ? target : flag ? 100 : 0;

それは一体どのように機能しますか?2 つの 3 項演算子が 1 つに結合されたようなもので、私には不可能だと思いましたか?

4

3 に答える 3

4

2番目の質問です。これはおそらくそれをより明確にするでしょう:

this.target = (target ? target : (flag ? 100 : 0));

そうです、ネストされた三項演算子です!言葉で書かれています:

this.target =(targetは真の値ですか?次にtargetを使用します。そうでない場合は、最後の部分の結果を使用します->(フラグは真の値ですか?100を使用します。それ以外の場合は0を使用します))。

于 2012-08-07T09:32:06.810 に答える
3

名前空間と考えてください。キーワードは、this自己呼び出し関数が返すオブジェクトリテラルを参照します。これはthis.target、グローバル名前空間(または定義されたスコープfadeEffect)でオブジェクトプロパティとしてアクセスできることを意味しますfadeEffect.targetが、外部スコープに存在する可能性のある他の変数には干渉しません。

2つのメソッドは、返されたオブジェクトの新しいプロパティを設定します。これですべてです。個人的には、これは悪いコードだと思います...この例ではクロージャがより良い選択でした:

var fadeEffect=function(){
    var elem,target,flag,alpha,si;//make private
    return{
        init:function(id, flag, target){
            elem = document.getElementById(id);
            clearInterval(elem.si);
            target = target ? target : flag ? 100 : 0;
            flag = flag || -1;
            alpha = elem.style.opacity ? parseFloat(elem.style.opacity) * 100 :0;
            si = setInterval(function(){fadeEffect.tween()}, 20);
        },
        tween:function(){
            if(alpha == target){
                clearInterval(si);//this.elem.si doesn't add up, init defines it as this.si
            }else{
                var value = Math.round(alpha + ((target - alpha) * .05))+ (1 * flag);
                elem.style.opacity = value / 100;
                elem.style.filter = 'alpha(opacity=' + value + ')';
                alpha = value
            }
        }
    }
}();

これは同じことをしますが、他のコードがターゲットの値に干渉したり、間隔を台無しにしたりすることはできません...thisこの場合、キーワードは必要ないと言うのは正しいですが、これはJSクロージャに慣れていないか、少なくともそれらがどのように機能するかについて不安であると書いています。このコードは、シングルトンパターンを効果的にシミュレートするか、少なくともオブジェクトリテラルをクラスのインスタンスとして扱います。私の推測では、著者は古典的なOOPに精通していますが、プロトタイプの継承には精通していません。とにかく、上記のコードはより安全であり、より安全である方が良い私見


ネストされた三項については、JSLintを使用して以下のコードを確認しました。これは、さらに短く、より明確な代替案を提案しました。デフォルトの演算子を使用し、その後に三項を使用します。

 //JSLint recommends this
 target = argTarget || argFlag ? 100 : 0;
 //over nested ternary
 target = argTarget ? argTarget : argFlag ? 100 : 0;

とにかく、これは同じコードですが、危険なthis構造を使用するだけでなく、JavaScriptの驚くほど強力な機能の1つであるクロージャーを使用しているので、それらを使用して何ができるかを詳しく調べる価値があります。

var fadeEffect=(function()
{
    var elem,target,flag,alpha,si;//make private
    //define private 'methods': functions will be available, but only to return object
    //tween shouldn't be callable, it's a callback for the interval, which is set in init
    function tween()
    {
        if(alpha === target)
        {
           clearInterval(si);//this.elem.si doesn't add up, init defines it as this.si
        }
        else
        {
            alpha = Math.round(alpha + ((target - alpha) * 0.05))+ (1 * flag);
            //don't know why 1*flag is needed here, suggest:
            //alpha = Math.round(alpha + ((target - alpha) * 0.05)) + (+flag); +flag coerces to numeric
            elem.style.opacity = alpha / 100;
            elem.style.filter = 'alpha(opacity=' + alpha + ')';
        }
    }
    return{
        init:function(id, argFlag, argTarget)//arguments !== closure scope
        {
            if (si !== undefined && si !== null)
            {
                clearInterval(si);
            }
            elem = document.getElementById(id);
            //JSLint recommends this:
            target = argTarget || argFlag ? 100 : 0;
            //over nested ternary
            target = argTarget ? argTarget : argFlag ? 100 : 0;
            flag = argFlag || -1;
            alpha = elem.style.opacity ? parseFloat(elem.style.opacity) * 100 :0;
            si = setInterval(tween, 20);//just a reference to the tween function will do
        }
    };
})();
fadeEffect.init('someId',1,50);//will set things in motion
fadeEffect.tween();//undefined
console.log(fadeEffect.target);
fadeEffect.target = document.getElementById('someOtherId');//no problem, but won't change the value of var target

このように、tweenメソッドを呼び出すことはできませんが、間隔によって呼び出すことができます。オブジェクトとそのメソッド/関数が機能している要素は、オブジェクトに固有の外部操作によってオーバーライドされることはありません。これにより、より安全な構築が可能になります。さらに、実際に混乱させることができるのは1つのメソッドのみです。.initメソッドをオーバーライドすると、オブジェクトは役に立たなくなりますが、無害になります。それをコードと比較してください。両方のメソッドを台無しにする可能性がありますが、間隔はそのままにしておきます...これは悪いニュースです。間隔は、削除された可能性のあるコールバック関数を探してしまい、コードが惨めに失敗する原因になります。 :

//asume your code using this.tween();
fadeEffect.init('id',1,123);
delete fadeEffect.tween;
//inside fadeEffect:
setInterval(function(){fadeEffect.tween()}, 20);
//should be written as:
setInterval(fadeEffect.tween,20);
  // === setInterval(undefined,20); === :-(
于 2012-08-07T09:44:13.203 に答える
2

のもう 1 つの説明this.target = target ? target : flag ? 100 : 0;:

if(target){
  this.target = target;
}
else{  
  if(flag){
    this.target = 100;
  } else {
    this.target = 0;
  }
}
于 2012-08-07T09:37:15.107 に答える