名前空間と考えてください。キーワードは、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); === :-(