关于JavaScript中Function Declaration与Function Expression的进一步说明
2013-12-23 13:47
351 查看
转自:/article/4635271.html
我在1月12日发表了《解读ECMAScript[2]——函数、构造器及原型》一文,文中提到了函数声明(Function
Declaration)与函数表达式(Function Expression)的概念。在那篇文章中,重点对两者与ECMAScript内置对象Function之间的关系进行了论述,而对两者的区别未加以详细说明。昨天晚上对Web前端颇有研究的jee.chang.sh同学在GTalk上提醒了我这个问题,并说很多初学者经常因为未注意到两者的区别而犯错,希望我能在博客中阐述两者的区别。因此我决定单独写一篇文章来简要论述一下在《解读ECMAScript[2]——函数、构造器及原型》中未尽的事宜。
在讨论函数声明与函数表达式之前,我觉得有必要明确一下JavaScript中变量及对象的区别。具体来说:
JavaScript中的对象(Object)是一个实体,而变量(Variable)仅仅是一个用于保存值或对对象引用的符号(Symbol)。JavaScript的变量是松散类型的,这意味着变量符号可以任意指向不同类型的数据。
混淆变量与对象,常常会造成误用。例如在与一位朋友的讨论中,他写下如下代码试图切断原型链:
这位朋友的本意是将func的原型对象销毁,但是func.prototype = null一句并不能达到其目的,因为func.prototype只是JavaScript解释器提供给用户的一个以只读方式访问原型对象的指针符号,将其设为null,只是令这个符号不引用任何对象了,但实际func的原型对象并未被销毁。下图是对此原理的一个图示,虚线表示被切断的引用。
而且,func构造对象时并不是通过func.prototype去访问其原型,而是通过一个用户不可见的内部引用(具体实现依赖于解释器,上图假设为_proto)去访问的。这就好比C语言中只将指针置为null是不能释放内存一样,下面用一段C代码类比上面的过程:
JavaScript这一点和PHP很类似,熟悉PHP的朋友应该知道,PHP对变量的内部表示是一个zval结构体,JavaScript中的对象就相当于zval,而PHP中的变量同样是一个松散类型的符号,因此在PHP中单纯将变量设置为null并不能销毁其引用的变量,如需销毁需要显示使用unset或依靠GC机制。例如:
与PHP不同的是,几乎所有JavaScript解释器都不提供与PHP中unset对应的显式销毁对象的方法,因此需要等待GC机制进行垃圾回收时才能将不再用的对象销毁。
Function Declaration与Function Expression在绝大多数情况下没有区别,唯独的区别在创建Function对象的时机上。先看下列两段代码:
代码A:
代码B:
这两段代码几乎是一样的,但是使用函数声明的代码A运行正常,而使用函数表达式的代码B则会报错。这是因为以下事实:
JavaScript是一种解释型语言,函数声明会在JavaScript代码加载后、执行前被解释,而函数表达式只有在执行到这一行代码时才会被解释。
所以代码A相当于在执行sayHello()前已经建立了一个Function Object并赋给了变量sayHello,其对应代码如下:
而代码B在执行sayHello()还未存在Function Object和变量sayHello,因为JavaScript在第一次使用某变量时会建立此变量,所以此处建立变量sayHello,但其值时undefined,未引用任何对象,将其作为函数来调用当然会出错。另外,解释JavaScript时如果某个变量已经存在,则其前面的“var”关键字被忽略,所以B代码等价于下列代码:
除了什么时候可以被访问到外,JavaScript中的Function Declaration与Function Expression两种语法其实是等价的。另外,大多数浏览器支持将两种语法一起使用,如:
但是以上语法在Safari上会报错。因此为了浏览器兼容性考虑,任何时候都不要合并使用两种语法。
引子
我在1月12日发表了《解读ECMAScript[2]——函数、构造器及原型》一文,文中提到了函数声明(FunctionDeclaration)与函数表达式(Function Expression)的概念。在那篇文章中,重点对两者与ECMAScript内置对象Function之间的关系进行了论述,而对两者的区别未加以详细说明。昨天晚上对Web前端颇有研究的jee.chang.sh同学在GTalk上提醒了我这个问题,并说很多初学者经常因为未注意到两者的区别而犯错,希望我能在博客中阐述两者的区别。因此我决定单独写一篇文章来简要论述一下在《解读ECMAScript[2]——函数、构造器及原型》中未尽的事宜。
区分变量与对象
在讨论函数声明与函数表达式之前,我觉得有必要明确一下JavaScript中变量及对象的区别。具体来说:JavaScript中的对象(Object)是一个实体,而变量(Variable)仅仅是一个用于保存值或对对象引用的符号(Symbol)。JavaScript的变量是松散类型的,这意味着变量符号可以任意指向不同类型的数据。
混淆变量与对象,常常会造成误用。例如在与一位朋友的讨论中,他写下如下代码试图切断原型链:
而且,func构造对象时并不是通过func.prototype去访问其原型,而是通过一个用户不可见的内部引用(具体实现依赖于解释器,上图假设为_proto)去访问的。这就好比C语言中只将指针置为null是不能释放内存一样,下面用一段C代码类比上面的过程:
Function Declaration与Function Expression
Function Declaration与Function Expression在绝大多数情况下没有区别,唯独的区别在创建Function对象的时机上。先看下列两段代码:代码A:
JavaScript是一种解释型语言,函数声明会在JavaScript代码加载后、执行前被解释,而函数表达式只有在执行到这一行代码时才会被解释。
所以代码A相当于在执行sayHello()前已经建立了一个Function Object并赋给了变量sayHello,其对应代码如下:
相关文章推荐
- 关于JavaScript中Function Declaration与Function Expression的进一步说明
- C++: 关于function的declaration与definition的关系(函数声明和定义的关系)(并附一篇转载文章)
- 关于Xcode6编译变更 “Implicit declaration of function 'sysctl' is invalid in C99” 报错问题
- 关于javascript弹出窗口的一些参数说明
- Myeclipse10.0关于javascript的一个错误提示的Bug:Cannot return from outside a function or method
- 关于Javascript模块化和命名空间管理的问题说明
- 关于'for' loop initial declaration used outside C99 mode的说明
- 韩顺平 javascript教学视频_学习笔记18_js超级玛丽小游戏2_js面向对象的进一步说明
- javascript的function的说明
- 微软关于XP退役的进一步说明。
- 【javascript】关于Function.prototype.bind
- 关于JavaScript一个错误 Uncaught TypeError: form.submit is not a function
- 关于typedef的进一步说明
- 关于JavaScript中function的两种创建方式的解析
- 关于Javascript模块化和命名空间管理的问题说明
- 关于 implicit declaration of function --Which should not record for myself
- 关于编译时报implicit-function-declaration(隐式声明)错误的解决方法
- 关于 implicit declaration of function --Which should not record for myself
- 关于JavaScript中事件的一些重要说明
- What is the difference between a function expression vs declaration in JavaScript?