`
jindw
  • 浏览: 508337 次
  • 性别: Icon_minigender_1
  • 来自: 初到北京
社区版块
存档分类
最新评论

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

阅读更多
<script>
var test1 = 1;
function test1(){};//函数申明不能覆盖变量申明?
alert(test1);
</script>
<script>
var test2 = 1;
eval('function test2(){};');
alert(test2);//函数申明怎么又覆盖了变量申明?
</script>
分享到:
评论
28 楼 radar 2007-05-09  
<script>
alert(test1);
var test1 = 1;
function test1(){};//函数申明不能覆盖变量申明?
alert(test1);
</script>

看看这段代码怎么输出。


在看看
<script>
alert(test2);
var test2 = 1;
eval('function test2(){};');
alert(test2);//函数申明怎么又覆盖了变量申明?
</script>

再看看
<script>
alert(x)
alert(a)
alert(b)
alert(c)//根本没反映

var x=1;
function a(){}
var b=function(){};
eval('function c(){};');
</script>


eval在犀牛书中建议不要乱用,具体什么原因并没说。 可能这是原因之一。
27 楼 radar 2007-05-09  
http://www.iteye.com/topic/19506

首先:以下代码让我相信javascript有个预编译过程,不是完全按照顺序解释执行的。
代码

   1. <SCRIPT LANGUAGE="JavaScript"> 
   2. a(); 
   3. function a(){ 
   4.     alert(); 
   5. } 
   6. </SCRIPT> 


个人理解这个预编译过程不会象java/c#那样把代码编译成虚拟机认识的语言,更不会象vb,vc那样编译成更底层的语言。猜想只是把这个函数预装载到这段函数执行的全局环境中,在这个执行环境中,该函数被标识定义过,可以直接使用了。(看到网上很多人写的AOP的javascript实现,其实这个预编译过程才是翻译元数据最佳时候,可惜就javascript语言来讲,是有些落伍了)

这个文章主要讲变量的一些问题。变量说了,为什么函数可以,我变量就不可以呢。
代码

   1. <SCRIPT LANGUAGE="JavaScript"> 
   2. document.writeln(a); 
   3. var a=0; 
   4. </SCRIPT> 


为什么我要输出undefined呢?为什么我a就不可以预编译一把呢?
大家看看以下两段代码会输出什么呢啊???
代码

   1. <SCRIPT LANGUAGE="JavaScript"> 
   2. document.writeln(a); 
   3. a=0; 
   4. </SCRIPT> 

代码

   1. <SCRIPT LANGUAGE="JavaScript"> 
   2. document.writeln(a); 
   3. </SCRIPT>  

可能你运行试了,可能你本来就知道,a未定义。哈哈哈,好了。
现在我确信var a=0;被javascript解释器“预编译过”,至少是记录下来了。甚至把它的值设置为 undefined。“undefined”这个词名字取的很是让人误解,怎么能叫未定义呢,分明是javascript中所有变量的初始化值。关于 null与undefined的比较我实在不愿提了。
注意上面两段代码还反映一个现象。隐式声明的变量是在解释的时候才把自己定义为全局变量的。

关于函数与变量javascript预编译的不同处理,大家可以与java class的加载过程比较下。java也是对基本类型设出值,对象为null的。(不往远扯了)
26 楼 dlee 2007-05-09  
可能就是因为这个原因,在很多的Ajax组件库中都采用了使用匿名函数赋值的方法,因为这样做不容易被覆盖。

另外像Dojo这样的库都将全部的函数都放在某个名字空间变量中,例如:
dojo.byId或者dojo.io.bind,
虽然有很多Prototype Fans认为$函数才是最方便优雅的写法,但是dojo.byId用起来会更安全一些,因为开发者定义一个变量名称为dojo.byId是不可能的(变量名中不能出现“.”)。
25 楼 dlee 2007-05-09  
to Readonly:
与执行顺序无关。
症状是:只要创建了一个名称为xxx的普通变量,再以最初一楼代码中的那种方式创建名称为xxx的函数就是无效的(并没有创建这个函数),无论将这个函数声明放在哪里。只能通过用匿名函数明确地为xxx变量赋值,才可能绕过这个问题。

这个症状在IE和Firefox中是一致的。
24 楼 max.h.chen 2007-05-09  
如果存在函数不调用则不创建的原则呢?是不是就说过去了?
23 楼 Readonly 2007-05-09  
这个问题太奇怪了,偶下断点debug了一下,发现这个执行顺序完全可以用诡异来形容...外行看热闹,期待内行来讲讲门道了。

22 楼 max.h.chen 2007-05-09  
onclick事件监听的匿名函数注册在function test1(){};函数创建之前,如果是这样的话,就可以解析了。不过还有一点说不过去,就是最后只要函数function test1(){};被创建了,那么test1这个reference就会改变,那么点下按钮之后就应该是function。除非这个函数就没有被创建过。
21 楼 dlee 2007-05-09  
to BaSaRa:
确实又是一个不能自圆其说的情况,呵呵。
不过有一个通用的方法可以绕过这个问题,那就是采用匿名函数赋值的方法来做。最初的代码要改成这样:
<script>
var test1 = 1;
test1 = function() {};
alert(test1);
</script>

具体的原因,我们可以继续再探讨。
20 楼 BaSaRa 2007-05-09  
按dlee的说法,外部代码执行完后其它函数才会创建,那我还是以
<script>  
var test1 = 1;   
alert(test1);   
function test1(){};
</script>  


这段代码为例子吧

alert(test1)执行完后才创建test1函数,可是我在页面上创建一个按钮,在window.onload完毕后
(估计页面JS初始化完成了)手动触发按钮的onclick="alert(test1);"事件,这个时候test1还是1,并不是 function ,函数并没有被创建...

这个如何解释?

19 楼 radar 2007-05-09  
广义上的解释型语言是: 编译器和解释器为同一程序,中间码不保存为文件,而是在内存中,你感觉不到,就当解释语言理解了。如  python,javascript之类的

但如java,c# ,编译成 class,Il中间语言,你可以看到。性能稍好。

但如  c c++ 直接编译成操作系统可认识的指令,那当然最快了。

汇编是最快地。
18 楼 dlee 2007-05-09  
呵呵,严格说来,其实现在所有现代高级编程语言都有一个编译的步骤,几乎已经不存在纯粹的解释型语言了。
所以很多未执行的函数中存在代码错误,JavaScript引擎都能够及早报告。如果是解释型语言,是不会有这种行为的。

考虑到JavaScript存在的编译步骤,最初提到的JavaScript代码的这种行为的解释就变得很合理了,因为这些代码并不是逐句解释执行的。
17 楼 jindw 2007-05-09  
呵呵,算我见识浅陋,basic没见过。
争论这个也确实没意思。

感觉,现在说解释型,编译型,不好用来区分语言的种类了。
大多语言都同时具有两种特征。

动态语言,静态语言来区分或许更合适。
16 楼 dlee 2007-05-09  
jindw 写道
按你这种说法,就没有解释型语言了,我感觉,只要没有编译成中间文件,直接用源代码部署的语言,都应该归为解释型语言。

java这样有编译过程的语言,很多书上说它有解释型的特征呢。解释字节码嘛,也有道理。

兄弟,这一点你不需要跟我争论,因为解释型语言和编译型语言有着严格的区分。

如果你在计算机启蒙阶段使用过解释型的Basic语言(不是Visual Basic),它是一种真正的解释型语言。对于代码是逐句翻译,逐句解释并执行的,因此它的执行效率非常低。
而对于Perl、JavaScript、Ruby来说,它们都是脚本语言,但是它们并不是解释型语言,而是编译型语言。在执行之前,它们有一个明显的编译步骤。

后来的这些脚本语言与Basic相比,正因为它们引入了预先对于全部代码的编译步骤,而不是像早期解释型语言那样逐句解释,这才使得它们的性能得到的大幅提升,才有可能有能力承担繁重的工作。
15 楼 jindw 2007-05-09  
to dlee:
按你这种说法,就没有解释型语言了,我感觉;你能列举个完全没有中间状态的例子?
只要没有编译成中间文件,直接用源代码部署的语言,都应该归为解释型语言。

java这样有编译过程的语言,很多书上说它有解释型的特征呢。解释字节码嘛,也有道理。
14 楼 dlee 2007-05-09  
to sp42:
你的这个解释也有一些问题。另外由于JavaScript引擎创建声明的函数采用的是异步的方式,有些错误你使用调试器未必能跟踪到。因为你进入到调试器中以后,函数肯定是已经创建好了。

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

以这种方式来实现,是一种效率较高的实现方式,因为编译或eval是一个相当慢的操作。
13 楼 jindw 2007-05-09  
在rhino实现里面,函数的变量申明和内部函数申明是分开来管理的。
应该有一个先后,但是初始化函数的位置,又还是原来的位置。

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

to sp42 你那个工具还没用过呢,看起来不错呢:)
在什么地方的?
12 楼 jindw 2007-05-09  
对了,dell,有没有ecma中文译本呢?
11 楼 sp42 2007-05-09  
引用
先执行完所有外部的代码之后,才会创建声明的函数的


不好意思,dlee,对于第一段代码,我这里的MSM(MS Script Editor)显示的是“先创建声明的函数”再执行其它代码。如下图:

可见已经有"test1"。然后“逐语句”走到 “var test1 = 1; ”这里,此时MSM报:


便是alert()是1的结果。
所以是后来的var test1 = 1;这句override掉 function test1(){}了,
其实相当于是:
<script> 
function test1(){};//函数申明不能覆盖变量申明?  
var test1 = 1;   
alert(test1);   
</script>  


这也证明了jindw第二次发的代码:
<script> 
alert(test1());//这样也行???? 
var test1 = 1; 
function test1(){return 'xxx'}; 
</script> 
 


JS引擎把function的声明的创建都放到前面了。
10 楼 jindw 2007-05-09  
哦,你的意思是说,这种奇怪的行为完全是解释引擎的主张了?

等有空了好好啃啃ecma262,看看这方面有没有明确的约定:)
9 楼 dlee 2007-05-09  
以前有个人曾经问过我,我在IE和Firefox上试过,行为都是这样的。

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

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

相关推荐

    高斯随机变量的特征函数

    高斯随机变量是服从正态分布的随机变量,其概率密度函数具有对称性和钟形特性,中心峰值位于均值处,方差决定了分布的宽度。 正态分布的概率密度函数(PDF)可以表示为: \[ f(x|\mu,\sigma^2) = \frac{1}{\sqrt{2\...

    408函数-递归调用-全局变量和局部变量

    ### 408函数-递归调用-全局变量和局部变量 #### 一、CLion环境下新建文件及函数管理 在CLion环境下新建文件,尤其是C/C++源文件,对于项目的组织和代码的管理非常关键。为了提高编程效率和调试效果,我们需要遵循...

    随机数个相互独立的随机变量之和的分布函数

    在概率论和统计学中,随机变量的分布函数是用来描述随机变量取值的概率规律的函数。当我们面对多个相互独立的随机变量时,了解它们之和的分布函数就变得尤为重要,因为这有助于我们理解和分析这些随机变量共同作用的...

    matlab构造含符号变量的函数并求值

    在MATLAB中,符号变量和符号函数的使用是数学建模和符号计算的重要部分。本文将详细介绍如何在MATLAB中构造含符号变量的函数并进行求值。 首先,我们需要了解什么是符号变量。在MATLAB中,符号变量允许我们进行符号...

    C# lua库 支持中文函数名中文变量

    本文将深入探讨“C# lua库 支持中文函数名中文变量”这一主题,基于lua 5.1版本,我们将讨论如何在C#中集成Lua,并支持中文的函数名和变量名。 首先,Lua是一种轻量级的脚本语言,以其简洁的语法和高效的执行性能而...

    python类和函数中使用静态变量的方法

    在Python编程语言中,类和函数的静态变量通常是指那些在多次调用中保持其值不变的变量。静态变量在其他面向对象的语言如Java或C#中比较常见,但在Python中,由于其动态特性的存在,实现静态变量的方式稍有不同。本篇...

    linux常用c函数 环境变量篇.txt

    ### Linux C函数环境变量...这些函数在编写Linux下的C程序时非常有用,可以帮助我们更灵活地管理和利用环境变量。在实际编程过程中,应当注意函数的正确调用顺序,并妥善处理错误情况,以确保程序的健壮性和安全性。

    MATLAB自定义函数及局部变量.docx

    在MATLAB中,变量可以分为局部变量和全局变量。如果一个函数内的变量没有特别声明,那么这个变量只在函数内部使用,即为局部变量。如果两个或多个函数共用一个变量(或者说在子程序中也要用到主程序中的变量,注意...

    LIN API共用函数库和变量定义

    针对日本瑞莎单片机r8c/23 开发的LIN网络通讯程序包括主节点和从节点,此文件为共用函数库和变量定义

    二维随机变量分布函数习题

    2. **联合分布函数和边缘分布函数**:联合分布函数F(x, y)给出了二维随机变量(X, Y)所有可能值的概率,而边缘分布函数F_X(x)和F_Y(y)分别表示X和Y的单独分布,可以通过对另一个变量积分得到,即F_X(x) = ∫F(x, y)dy...

    php变量缓存到文件的函数

    php变量缓存到文件的函数 SAVE函数有用哦。php变量缓存到文件的函数 SAVE函数有用哦。php变量缓存到文件的函数 SAVE函数有用哦。php变量缓存到文件的函数 SAVE函数有用哦。php变量缓存到文件的函数 SAVE函数有用哦。...

    authorware变量、函数大全

    用法 numlist=[1,2,3] AddLinear(numList,99,1) NumList为[99,1,2,3] numList:=[1,2,3] Addlinear(numList,99,6) NumList为[1,2,3,0,0,99] 相关函数 参见系统函数SortByProperty和SortByValue。

    函数自变量取值范围专题练习.doc

    这些知识点涵盖了函数自变量取值范围的基本原则和方法。在解决实际问题时,我们需要根据函数的具体形式,结合这些原则来确定自变量的允许取值。通过这些练习题,我们可以加深对函数定义域的理解,并能熟练地求解复杂...

    基于Python函数和变量名解析

    函数是Python为了代码最大程度的重用和最小化代码冗余而提供的基本程序结构,用于将相关功能打包并参数化 Python中可以创建4种函数: 1)、全局函数:定义在模块中,每个模块都是一个全局作用域,因此,全局作用域...

    复杂函数申明解析

    在C或C++编程语言中,函数声明的解析尤其是复杂声明的解析对于初学者和经验丰富的程序员都可能是个挑战。本文将带领读者逐步解析C/C++中的复杂函数声明,包括使用typedef、const关键字以及函数指针的高级用法,并...

    3.8 函数参数与变量的作用域(ppt).zip

    在编程语言中,函数参数与变量的作用域是至关重要的概念,它们直接影响到代码的可读性、维护性和正确性。作用域定义了变量在程序中的可见范围,而函数参数则是函数接收输入数据的方式。让我们深入探讨这两个主题。 ...

    JavaScript闭包函数访问外部变量的方法

    为了更加清晰地理解闭包和匿名函数在访问外部变量时的区别,我们可以参考两个经典的例子。第一个例子是通过数组存储闭包,然后遍历数组执行闭包,观察闭包对变量的引用情况。第二个例子是通过绑定事件处理器的方式,...

    Perl常用函数&特殊变量

    Perl常用函数&特殊变量,便于查阅

    人教版八年级下册数学教案:19.1.1变量与函数第一课时变量与常量.docx

    本节课的主要目标是让学生理解变量和常量的概念,并学习如何用一个变量表示出另一个变量。通过本节课的学习,学生将能够说出变量和常量的概念,并能够自己用一个变量表示出另一个变量。 变量是指在一个变化过程中,...

    在MFC下如何定义全局变量和全局函数

    在MFC(Microsoft Foundation Classes)框架下开发应用时,全局变量和全局函数的定义与普通C++项目有所不同,因为MFC项目的结构更为复杂,通常由多个文件构成,直接在类外部定义全局变量可能会导致编译错误或者链接...

Global site tag (gtag.js) - Google Analytics