把它看成是一個命名空間。關鍵字this
引用自調用函數返回的對象字面量。這意味着this.target
可以在全局名稱空間(或定義的fadeEffect
的任何作用域)中作爲對象屬性訪問:fadeEffect.target
,但它不會影響外部作用域中可能存在的其他變量。
這兩個方法設置了返回對象的新屬性,這就是它的全部。我個人覺得這是,好,壞的代碼......一個封閉會一直在這個例子中是更好的選擇:
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關閉,或者至少對他們的方式不安全工作。此代碼有效地模擬單例模式,或者至少將對象字面量視爲類的實例。我的猜測是,作者熟悉古典的面向對象,但不是原型繼承。總之,上面的代碼更安全,更安全的最好恕我直言
在您的嵌套三元的事情,我已經檢查下面使用的JSLint的代碼,並提出更短的,但更清晰的選擇:使用默認的運營商,其次是三元:
//JSLint recommends this
target = argTarget || argFlag ? 100 : 0;
//over nested ternary
target = argTarget ? argTarget : argFlag ? 100 : 0;
不管怎麼說,這是相同的代碼,只是不使用危險this
結構,但使用封閉,JavaScript的一個令人驚訝的強大功能BTW,值得仔細看看你可以用他們做什麼!
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); === :-(
是的,這正是我的想法。在這種情況下這不是必需的,但是我上面看過,它用於在這個命名空間中創建變量(屬性)。 this.elem.si是我認爲的一個錯誤,因爲它不會加在我身上。它被定義爲this.si.我喜歡你的代碼方式比編寫此代碼的人使用的更好。我有暴露於封閉和命名空間。我無法舒適地談論這些主題。 – W3Geek 2012-08-07 09:54:43
你說得對,說'這'不是必要的。你發佈的代碼創建一個對象字面值,但被寫爲一個構造函數。這只是令人困惑和不好的做法。如果你知道你將需要什麼變量,請使用閉包。你的對象現在的工作方式,你可能會意外地改變'target'屬性,導致間隔在一個不同的元素上突然淡出,從而結束了2個半褪色元素。使用閉包可以保護你免受此影響。我會將這段代碼更加深入到一個可用的,安全的版本(這個版本仍然有一些問題需要解決) – 2012-08-07 10:11:40
不知道這個答案是否太好,無法被接受... – ted 2012-08-07 20:01:40