2012-08-07 94 views
2

我在搜索如何使用JavaScript淡入淡出元素,並且遇到了這個函數(object)。我開始想知道它是如何工作的?此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 
     } 
    } 
} 
}(); 

我知道這是自我調用,只能用兩種方法返回一個對象。我主要關心的是爲什麼它使用this關鍵字?我假設'this'關鍵字是對象名稱「fadeEffect」的佔位符。我會理解,如果'這'被用來創建多個對象......但爲什麼它在這裏使用?

另一件事困擾我,這是三元運算符...

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

的到底是如何工作的?這就像兩個三元運算符合併成一個我從未想到過的運算符?

回答

3

把它看成是一個命名空間。關鍵字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); === :-(
+0

是的,這正是我的想法。在這種情況下這不是必需的,但是我上面看過,它用於在這個命名空間中創建變量(屬性)。 this.elem.si是我認爲的一個錯誤,因爲它不會加在我身上。它被定義爲this.si.我喜歡你的代碼方式比編寫此代碼的人使用的更好。我有暴露於封閉和命名空間。我無法舒適地談論這些主題。 – W3Geek 2012-08-07 09:54:43

+0

你說得對,說'這'不是必要的。你發佈的代碼創建一個對象字面值,但被寫爲一個構造函數。這只是令人困惑和不好的做法。如果你知道你將需要什麼變量,請使用閉包。你的對象現在的工作方式,你可能會意外地改變'target'屬性,導致間隔在一個不同的元素上突然淡出,從而結束了2個半褪色元素。使用閉包可以保護你免受此影響。我會將這段代碼更加深入到一個可用的,安全的版本(這個版本仍然有一些問題需要解決) – 2012-08-07 10:11:40

+0

不知道這個答案是否太好,無法被接受... – ted 2012-08-07 20:01:40

4

至於你的第二個問題。這可能會使它更清晰:

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

所以,是一個嵌套的三元運算符!寫出來的文字如下:

this.target =(目標是一個真值?然後使用目標。如果不是,那麼使用最後一部分的結果 - >(是標誌真值?使用100.否則,使用0))。對於this.target = target ? target : flag ? 100 : 0;

+0

它是如何工作的? – W3Geek 2012-08-07 09:33:00

+1

寫出來給你。應該說清楚... – 2012-08-07 09:36:41

2

還有一個解釋:

if(target){ 
    this.target = target; 
} 
else{ 
    if(flag){ 
    this.target = 100; 
    } else { 
    this.target = 0; 
    } 
}