靠谱的软件下载站
当前位置:  IEfans/IE专区/IE相关/低版本IE浏览器的命名函数表达式句柄问题

低版本IE浏览器的命名函数表达式句柄问题

IE相关 互联网 2014-03-21 阅读(1636)
关于callee的效率问题,必须使用命名函数来解决,而直接使用命名函数不环保,因此MDN上建议使用命名函数表达式来解决。但是IE8-并没有兼容好命名函数表达式,依然使用者传统IE的诡异行为,低版本IE浏览器会把命名函数表达式的函数名作为变量定义到代码所在的作用域下,所以命名函数表达式只能用在一些现代化的项目中。 咱先来看一段代码
~function f(){alert("表达式1")};

function f(){alert("语句")};

~function f(){alert("表达式2")};

f();
  这个代码会输出什么呢?结果是现代浏览器中输出“语句”,IE8-中输出“表达式2”。这就是因为IE8-中对命名函数表达式的兼容有问题!函数有语句和表达式两种定义形式,作为语句时是与var一样预处理的,作为表达式时就是正常的执行到时处理。上面这段代码中给function前面加上“~”运算符它就变成了表达式。但是呢,这个表达式却有函数名,这就是命名函数表达式的概念。IE8-中会把这个函数名释放到当前作用域中,所以最后执行到的函数定义是“表达式2”的函数定义,它覆盖掉之前定义的f,所以IE8-才有输出“表达式2”的结果。而现代浏览器对它的解析就是一个正宗的命名函数表达式,这个函数名不会被释放到当前作用域中,而是仅在自身函数内有效。比如:
var f;
(function f(){
  alert(f==arguments.callee); //true
})();
alert(f); //undefined
  它可以达到和callee完全相同的效果,而且不会影响所在的作用域,并且不用经过arguments而带来不必要的性能开销,所以MDN才建议使用命名函数表达式来替代callee。但是这仅限于现代浏览器,对于需要兼容IE8-的项目我依然建议使用callee。当然,对于一些非常有必要做细节性能优化的代码也可以使用命名函数的方式来避开arguments。 除此之外还有另一个问题,由于表达式定义与函数本身的定义是两个不同的定义,这就产生了两个不同的句柄。
var a,b;
(a=function b(){
  alert(a.toString()==b.toString()); //true
  alert(a==b); //IE<9?false:true
})();
  在全局作用于下,变量a是函数表达式的结果,变量b是由function语句定义出来的东西(在支持命名函数表达式的浏览器上b是函数内的局部变量)。它们的函数体、参数列表、作用域,全都相同,但却是不同的对象。或者说这个函数字面量被使用了两次,就像
var i,s,a,b;
for(i in s=["a","b"])window[s[i]]=function(){
  alert(a.toString()==b.toString()); //true
  alert(a==b); //false
};
a();
  这会带来什么问题呢?比如事件绑定的问题
document.addEventListener
  ?document.addEventListener("click",function callee(){
    alert(callee);
    document.removeEventListener("click",callee); //正常注销事件
  })
  :document.attachEvent("onclick",function callee(){
    alert(callee);
    document.detachEvent("onclick",callee); //句柄不同无法注销事件
  });
  所以在使用命名函数表达式且兼容低版本IE时就要谨慎,不要因为IE也能定义出函数名而忽略了句柄不同的问题。 via:web-tinker

标签:JavaScriptIE Web

Copyright © 1998-2017 www.iefans.net All Rights Reserved 湘ICP备13012168号-17