2

我之前正在搜索如何使用 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;

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

4

3 回答 3

4

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

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

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

this.target =(目标是真实值吗?然后使用目标。如果不是,则使用最后一部分的结果->(标志是真实值吗?使用100。否则,使用0))。

于 2012-08-07T09:32:06.810 回答
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 闭包,要么至少对它们的工作方式不安全。此代码有效地模拟了单例模式,或者至少将对象字面量视为类的实例。我的猜测是,作者熟悉经典 OOP,但不熟悉原型继承。无论如何,上面的代码更安全,更安全更好恕我直言


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

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

无论如何,这里是相同的代码,只是没有使用危险的this构造,而是使用了闭包,顺便说一句,这是 JavaScript 非常强大的功能之一,值得仔细看看你可以用它们做什么!

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方法只能通过间隔调用,并且对象及其方法/函数正在其上工作的元素永远不会被外部操作覆盖,它们是对象固有的。这使得构造更安全,更重要的是,您只能真正搞砸一种方法:覆盖该.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); === :-(
于 2012-08-07T09:44:13.203 回答
2

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

if(target){
  this.target = target;
}
else{  
  if(flag){
    this.target = 100;
  } else {
    this.target = 0;
  }
}
于 2012-08-07T09:37:15.107 回答