日期:2014-05-16  浏览次数:20406 次

JScript的函数声明和函数表达式

http://hax.iteye.com/blog/230182 【2008-08-19 16:11

我(博文作者)以前也试验过,不过这种用法很少很变态,所以基本没去关注它,var f1=function f1(){} ?一般用var或function其中一种来声明,不会两种同时用。两种同时用的会让ie很郁闷,其他浏览器倒没发现什么问题。

?

JScript在函数声明和函数表达式方面不合ECMA标准,这已经是一个老生常谈的话题了。最近aimingoo谈到eval问题的时候再一次触及到这个问题。?

大体就是 eval('(function (){})') 不返回函数对象,但是 eval('(0, function (){})') 却返回函数对象。此外,还有 eval('(function f(){})') 会在当前执行环境中产生 f 指向一个函数(当然,按照标准是不应该有的)。?

从现象上看,这表示JScript并没有把孤立的“(function (){})”作为function表达式。按照规范,(function(){})就是一个表达式,但是遗憾的是对于JScript来说,括号还不够,一定得有运算符介入或者语句expect一个表达式时,比如简单的逗号运算符、return语句之类的,才会被认为是表达式。?

此外“(function f(){})”按照规范应该也被认为是一个function表达式,但是JScript的行为却好像是一个函数声明。?

这里就有有趣的问题了。?

0,function f1(){}?

这样一个语句中,究竟是函数表达式还是函数声明呢??

答案是:两者皆是。?

当然这仅是从效果上说,因为本来这样的行为就不符合标准的定义。?

不过更微妙的问题是,这个表达式返回的函数对象和所声明的f1函数,其实并非同一个函数!?

对此,你可以在IE浏览器的地址栏里执行:javascript:alert(eval('0,function f1(){}')==f1),结果是false。?

也就是说function表达式产生了一个不同于function声明的结果——这里产生了两个不同的函数对象!?

回想到我以前对于with语句行为的测试,可以确认,JScript 5.0到5.5的时候,对function声明和function表达式的行为做了很大的修订,这可能是上述奇怪表现的源头。不过我手头没有JScript 5.0,所以无法做进一步的确认。?

另一个例子是:javascript:alert(eval('(function f1(){return arguments.callee==f1})()'));alert(f1())?
返回结果false和true。?

注意,这边的不相等,并非COM对象包装所造成的假象(比如两次读取event包装对象不相等,或者跨window/frame所造成的问题),而真的是两个函数,其实际执行效果其实也是不同的(虽然这里这个例子无法表现出来,但是如果加上with语句就会有差别了)。?

产生这个用于函数表达式的函数,和函数声明所产生的函数一样,是需要CPU资