将其视为命名空间。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); === :-(