论坛首页 Web前端技术论坛

函数申明和变量申明的微妙区别

浏览 17181 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-05-10  
另外,变量定义和变量赋值也是两个过程。var a; 是变量定义,a=1; 是变量赋值,var a=1; 是变量定义和变量赋值。虽然你写在一起,但是这个过程在js解析器解析的过程中也是分两步完成的,变量定义和函数定义是首先完成的,接下来执行的才是变量赋值。
0 请登录后投票
   发表时间:2007-05-10  
js 代码
 
  1. var a = function() {  
  2. };  
  3.   
  4. function a() {  
  5. }  

这两种申明在效率上有差别吗 ?
我已经习惯第一种了,因为在我看来,function也是一种基本类型。
0 请登录后投票
   发表时间:2007-05-10  
这两种有差别,

var a = funciton() {}; 是定义一个变量a,定义一个匿名函数,然后将匿名函数赋值给变量a。

而 function a(){} 只是声明一个名字为a的函数。

function a(){} 比 var a = funciton() {}; 执行效率高一点点。但是 var a = funciton() {}; 这种方式更灵活一些。
0 请登录后投票
   发表时间:2007-05-16  
引用
netfishx(151431) 14:45:28
哦,这个我也早就想过
netfishx(151431) 14:45:47
某个老外大牛就很坚定的说,js是有预编译的
netfishx(151431) 14:46:02
但在不同的环境下,顺序又有所不同
0 请登录后投票
   发表时间:2007-05-21  
dlee 写道
是的,这就是上面我最后补充的一句话的情况:
引用
当然,如果在外部的代码中包含有函数调用,其调用的这个函数是会在调用之前创建的。



你之前的描述是错误的(就ecma规范而言,实际引擎怎么实现,偶们都不清楚)。
根据ecma-262规范edition 3,函数声明(注意var x = function () {}是函数表达式,不是函数声明)会被放到函数体或者代码块的最前端。所以不管外部代码有没有函数调用,都是先创建函数声明所声明的函数(靠,绕口令了)。
0 请登录后投票
   发表时间:2007-05-21  
jindw 写道
没找到合适的解释


你没有找仔细啊,呵呵。
0 请登录后投票
   发表时间:2007-05-21  
dlee 写道
以前有个人曾经问过我,我在IE和Firefox上试过,行为都是这样的。

我猜想应该是考虑到执行效率的原因。这样做将创建声明函数(通过eval类似的机制)的工作放在最后,这部分工作可以以异步的方式来做,而不会影响到页面的render,而外部的代码在统一eval之后也可以尽快执行。

所以做JavaScript开发,不应该对函数创建的时机作出假设。而且函数创建的行为可能是异步的,执行到函数声明之后的这条语句时,函数尚未创建是完全有可能的。



同上,你的论断是错误的。

函数声明不管在哪里,都等价于放在该代码块或函数体的最前端。这里不存在异步的问题。而函数表达式则是另一回事情,可以认为是执行到该语句才创建的。

应该说这样一种设计是不太直观的,令人有些混淆,但是目前的现实就是如此。

这里存在两个例外,第一个是eval,eval中如果有函数声明,也是到eval执行的时候才起作用。但是eval内部仍旧是遵循我说的这个规则的。例如 eval('test1(); function test1(){...}'); 这个代码是ok的。另外一个是,按照标准,function声明是不能在statement里的,也就是说如下代码都是错误的:
if (x > 1) {
  function test() {...}
}

with (x) {
  function test() {...}
}


但是ie和moz都接受这个代码(有少数引擎不行,似乎safari就不行),其处理方式却可能不相同,这是spec以外的部分,所以也无话可说。
0 请登录后投票
   发表时间:2007-05-21  
jindw 写道
在rhino实现里面,函数的变量申明和内部函数申明是分开来管理的。
应该有一个先后,但是初始化函数的位置,又还是原来的位置。

初试化变量的时候,正如dlee所说,创建了一个空函数。

to sp42 你那个工具还没用过呢,看起来不错呢:)
在什么地方的?



没错,这就是spec没说的那部分。js2.0似乎会明确的确认这一点。

这个问题最影响的一点是当时function的scope到底是什么。例如包裹在with之内的function声明,到底是否受到with影响,ff引擎、jscript 5.5+、opera(我只验证过9.0)都是受到的。safari没有测试过。但是jscript 5.0就不受影响。我的pies的内部import特性就依赖于这个标准没有规定的危险特性,呵呵,所以pies在jscript 5的话,就只能用外部import,不能可靠的使用内部import。

sp42的工具就是ms script editor,office或者visual stuidio会带。可以给jscript断点,用来探索jscript的各种bug是不错的,呵呵。
0 请登录后投票
   发表时间:2007-05-21  
dlee 写道
to sp42:
你的这个解释也有一些问题。另外由于JavaScript引擎创建声明的函数采用的是异步的方式,有些错误你使用调试器未必能跟踪到。因为你进入到调试器中以后,函数肯定是已经创建好了。

我再给出一种可能的解释。很多人认为JavaScript是一种解释型的语言,其实JavaScript完全是一种编译型的语言,它每次都是要将代码先编译到内存后然后才执行的。我估计它是将所有的外部代码也放在一个匿名函数之中来编译的,然后立即执行这个匿名函数。而其他的函数,除了在匿名函数中调用到(直接或间接)的以外,都是放在匿名函数执行完之后才以异步的方式来创建的。

以这种方式来实现,是一种效率较高的实现方式,因为编译或eval是一个相当慢的操作。



不知道您老是怎么得出函数声明是异步的这个结论。至少从ecma-262e3规范和jscript的表现,我无法看出这点。相反,ecma规范是要求函数声明被预先处理的。

关于你说的js的编译问题,我认为你有点夸大了,解释和编译没有很大的分界线,只要保证语义不变,行为一致就可以了。但是js的编译至多类似于java的字节码,甚至连jit也达不到(少数特例js引擎除外),所以你这样说编译是误导的。至于你估计的那个异步过程,我认为是纯粹想像,没有任何证据,而jscript调试器给出的反例你的解释十分无力。
0 请登录后投票
   发表时间:2007-05-21  
dlee 写道
呵呵,严格说来,其实现在所有现代高级编程语言都有一个编译的步骤,几乎已经不存在纯粹的解释型语言了。
所以很多未执行的函数中存在代码错误,JavaScript引擎都能够及早报告。如果是解释型语言,是不会有这种行为的。

考虑到JavaScript存在的编译步骤,最初提到的JavaScript代码的这种行为的解释就变得很合理了,因为这些代码并不是逐句解释执行的。



但是这个步骤并不一定是“编译”,至少ecma规范管这个步骤叫 verify (记忆中)。


我个人认为,你只能说它不是一个传统的纯解释性的语言,但也不能说js是编译语言呀。
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics