这个JavaScript如何运作?

时间:2012-08-07 09:29:57

标签: javascript ternary-operator

我正在寻找如何使用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'用于创建多个对象......但为什么在这里使用它?

困扰我的另一件事是这个三元运算符......

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

这是怎么回事?这就像两个三元运算符组合成一个我从未想过可能的运算符?

3 个答案:

答案 0 :(得分:4)

至于你的第二个问题。这可能会更清楚:

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

是的,一个嵌套的三元运算符!用文字写出:

this.target =(目标为真值?然后使用目标。如果没有,则使用最后一部分的结果 - &gt;(标记为真值?使用100.否则,使用0))。< / p>

答案 1 :(得分: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关键字不是&#39;在这种情况下需要,但我认为写这篇文章的人要么不熟悉JS闭包,要么至少不确定它们是如何工作的。此代码有效地模拟单例模式,或者至少将对象文字视为类的实例。我的猜测是,作者熟悉经典的OOP,但不熟悉原型继承。无论如何,上面的代码更安全,更安全是更好的恕我直言


关于嵌套三元组的问题,我使用JSLint检查了下面的代码,它提出了一个更短但更清晰的替代方法:使用默认运算符,然后是三元运算符:

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

无论如何,这里的代码相同,只是没有使用危险的this构造,而是使用一个闭包,一个JavaScripts令人惊讶的强大功能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); === :-(

答案 2 :(得分:2)

this.target = target ? target : flag ? 100 : 0;的另一个解释:

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