容易被忽略的JS脚本特性


Posted in Javascript onSeptember 13, 2011

一、容易被忽略的局部变量

var a = 5; 
(function(){ 
alert(a); 
var a = a ++; 
alert(a); 
})() 
alert(a);

思考这段代码的执行结果。
执行后,看看是否和你想象的一致?
ok,这段代码里核心的知识点是 var a = a++,其中两个变量 a 都是匿名函数内部的局部变量,是同一个,和全局变量 a 是不一样的。
为什么?我们来看看ECMA规范对变量声明语句的定义:
Description 
If the variable statement occurs inside a FunctionDeclaration, the 
variables are defined with function-local scope in that function, as 
described in s10.1.3. Otherwise, they are defined with global scope 
(that is, they are created as members of the global object, as described 
in 10.1.3) using property attributes { DontDelete }. Variables are 
created when the execution scope is entered. A Block does not define a new 
execution scope. Only Program and FunctionDeclaration produce a new 
scope. Variables are initialised to undefined when created. A variable with 
an Initialiser is assigned the value of its AssignmentExpression when the 
VariableStatement is executed, not when the variable is created.

声明中提到:进入作用域环境后,变量就会被创建,并赋予初始值undefined。在变量声明语句执行时才会把赋值表达式的值指派给该变量,而并不是在该变量被创建时。
因此上面的代码可以等价于:
var a; 
a = 5; 
(function(){ 
var a; 
alert(a); 
a = a ++; 
alert(a); 
})() 
alert(a);

这样应该会更容易理解了。
二、容易被忽略的全局变量
(function(){ 
var a = b = 5; 
})() 
alert(b);

这是玉伯几天前分享到的知识点,蛮有意义的,在此也做个分析。
首先,考虑执行结果为什么是:5。
ok,原因出在 var a = b = 5 这句。
为深入分析这个语句,我们继续要参照ECMA规范对声明语句的定义:
var a = b = 5;等同为 var a; a = b = 5;两条语句,后者是赋值表达式,其在ECMA中的定义是这样的:
Simple Assignment ( = ) 
The production AssignmentExpression : LeftHandSideExpression = 
AssignmentExpression is evaluated as follows: 
1. Evaluate LeftHandSideExpression. 
2. Evaluate AssignmentExpression. 
3. Call GetValue(Result(2)). 
4. Call PutValue(Result(1), Result(3)). 
5. Return Result(3).

对于a = b = 5;先执行左边表达式 a,这是一个标识符表达式,根据规范第 10.1.4,其执行方式如下:
During execution, the syntactic production PrimaryExpression : Identifier 
is evaluated using the following algorithm: 
1. Get the next object in the scope chain. If there isn't one, go to step 5. 
2. Call the [[HasProperty]] method of Result(1), passing the Identifier as 
the property. 
3. If Result(2) is true, return a value of type Reference whose base 
object is Result(1) and whose property name is the Identifier. 
4. Go to step 1. 
5. Return a value of type Reference whose base object is null and whose 
property name is the Identifier.

搜寻作用域链,找到最近的一个 a 的引用,很明显,在匿名函数内部作用域就可以找到,于是变量 a 确定下来。
接着再执行右边的表达式 b = 5 ,还是一个赋值表达式,重复赋值规则第一步,因为变量 b 在匿名函数环境内未声明过,所以接着去 window 全局环境下去找 window.b ,被隐式声明为全局变量,最后赋值为 5,根据规则第五步,表达式的结果也会再赋值给 a。最终达到 a 和 b 都为 5 ,区别是 a 是局部变量,而 b 是全局变量。
我们再来理一下 (function(){var a = b = 5})() 表达式内部整体的执行顺序:
1.匿名函数内创建变量a;
2.赋予初始值undefined;
3.取得变量a的引用; //a
4.取得变量b的引用; //window.b
5.对数字5求值;
6.赋值5给b的引用:window.b;
7.返回b = 5的结果5给a的引用:a;
8.返回a = 5的结果5;
很明显,中间的一个步骤使得变量 b 被声明为全局变量,明白之后,我们不难找到代码的优化点:只需将变量 b 显式声明为局部变量:
(function(){ 
var a,b; 
a = b = 5; 
})()
Javascript 相关文章推荐
JSON 编辑器实现代码
Dec 06 Javascript
根据出生日期自动取得星座的js代码
Jul 20 Javascript
jquery学习笔记 用jquery实现无刷新登录
Aug 08 Javascript
jquery的$getjson调用并获取远程的JSON字符串问题
Dec 10 Javascript
iframe里面的元素触发父窗口元素事件的jquery代码
Oct 19 Javascript
Js类的静态方法与实例方法区分及jQuery拓展的两种方法
Jun 03 Javascript
jQuery遍历节点树方法分析
Sep 08 Javascript
微信小程序 Buffer缓冲区的详解
Jul 06 Javascript
微信小程序开发animation心跳动画效果
Aug 16 Javascript
javaScript中"=="和"==="的区别详解
Mar 16 Javascript
微信 jssdk 签名错误invalid signature的解决方法
Jan 14 Javascript
原生js实现下拉框选择组件
Jan 20 Javascript
Javascript学习笔记-详解in运算符
Sep 13 #Javascript
使用原生javascript创建通用表单验证——更锋利的使用dom对象
Sep 13 #Javascript
ie下动态加态js文件的方法
Sep 13 #Javascript
使用Json比用string返回数据更友好,也更面向对象一些
Sep 13 #Javascript
TextArea不支持maxlength的解决办法(jquery)
Sep 13 #Javascript
JQuery与JSon实现的无刷新分页代码
Sep 13 #Javascript
js Event对象的5种坐标
Sep 12 #Javascript
You might like
如何选购合适的收音机
2021/03/01 无线电
利用php实现禁用IE和火狐的缓存问题
2012/12/03 PHP
解析php中用PHPMailer来发送邮件的示例(126.com的例子)
2013/06/24 PHP
PHP实现多关键字加亮功能
2016/10/21 PHP
PDO::prepare讲解
2019/01/29 PHP
【消息提示组件】,兼容IE6/7&&FF2
2007/09/04 Javascript
Table冻结表头示例代码
2013/08/20 Javascript
javascript判断数组内是否重复的方法
2015/04/21 Javascript
jQuery实现带动画效果的多级下拉菜单代码
2015/09/08 Javascript
谈谈我对JavaScript原型和闭包系列理解(随手笔记6)
2015/12/20 Javascript
第六章之辅组类与响应式工具
2016/04/25 Javascript
JavaScript正则表达式小结(test|match|search|replace|split|exec)
2016/12/08 Javascript
fckeditor部署到weblogic出现xml无法读取及样式不能显示问题的解决方法
2017/03/24 Javascript
node.js利用socket.io实现多人在线匹配联机五子棋
2018/05/31 Javascript
微信小程序自定义组件之可清除的input组件
2018/07/17 Javascript
基于react项目打包css引用路径错误解决方案
2020/10/28 Javascript
[02:50]2014DOTA2 TI预选赛预选赛 大神专访第一弹!
2014/05/21 DOTA
[02:38]DOTA2亚洲邀请赛小组赛精彩集锦:Wings完美团击溃对手
2017/03/29 DOTA
python中的多线程实例教程
2014/08/27 Python
一个超级简单的python web程序
2014/09/11 Python
用python实现百度翻译的示例代码
2018/03/09 Python
python引入不同文件夹下的自定义模块方法
2018/10/27 Python
Python图像处理之图像的缩放、旋转与翻转实现方法示例
2019/01/04 Python
使用python将excel数据导入数据库过程详解
2019/08/27 Python
python3 求约数的实例
2019/12/05 Python
解决运行出现'dict' object has no attribute 'has_key'问题
2020/07/15 Python
聊聊python中的循环遍历
2020/09/07 Python
Pycharm的Available Packages为空的解决方法
2020/09/18 Python
Python实现淘宝秒杀功能的示例代码
2021/01/19 Python
Lookfantastic葡萄牙官方网站:欧洲第一大化妆品零售商
2018/03/17 全球购物
小学教育毕业生自荐信
2013/11/18 职场文书
缓刑人员的思想汇报
2014/01/11 职场文书
2014年学校食堂工作总结
2014/11/25 职场文书
小升初自荐信怎么写
2015/03/26 职场文书
2015年档案管理工作总结
2015/04/08 职场文书
病假条格式范文
2015/08/17 职场文书