2012-08-07 55 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; 
    } 
}