容易被忽略的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 相关文章推荐
Textbox控件注册回车事件及触发按钮提交事件具体实现
Mar 04 Javascript
使用Jquery实现点击文字后变成文本框且可修改
Sep 21 Javascript
jQuery实现仿淘宝带有指示条的图片转动切换效果完整实例
Mar 04 Javascript
javascript实现淡蓝色的鼠标拖动选择框实例
May 09 Javascript
JavaScript正则表达式之multiline属性的应用
Jun 16 Javascript
Angularjs通过指令监听ng-repeat渲染完成后执行脚本的方法
Dec 31 Javascript
Node.js中使用mongoose操作mongodb数据库的方法
Sep 12 Javascript
JS设计模式之观察者模式实现实时改变页面中金额数的方法
Feb 05 Javascript
vue中如何实现后台管理系统的权限控制的方法示例
Sep 19 Javascript
详解IOS微信上Vue单页面应用JSSDK签名失败解决方案
Nov 14 Javascript
Layui数据表格判断编辑输入的值,是否为我需要的类型详解
Oct 26 Javascript
js作用域及作用域链工作引擎
Jul 07 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
第十一节 重载 [11]
2006/10/09 PHP
用libTemplate实现静态网页的生成
2006/10/09 PHP
PHP与SQL语句常用大全
2016/12/10 PHP
laravel如何开启跨域功能示例详解
2017/08/31 PHP
如何重写Laravel异常处理类详解
2020/12/20 PHP
一些技巧性实用js代码小结
2009/10/14 Javascript
juqery 学习之三 选择器 可见性 元素属性
2010/11/25 Javascript
ASP.NET MVC中EasyUI的datagrid跨域调用实现代码
2012/03/14 Javascript
jquery重新播放css动画所遇问题解决
2013/08/21 Javascript
jQuery获取页面元素绝对与相对位置的方法
2015/06/10 Javascript
jQuery表单验证功能实例
2015/08/28 Javascript
JavaScript的Backbone.js框架的一些使用建议整理
2016/02/14 Javascript
JS平滑无缝滚动效果的实现代码
2016/05/06 Javascript
AngularJS 最常用的八种功能(基础知识)
2017/06/26 Javascript
实例详解JSON取值(key是中文或者数字)方式
2017/08/24 Javascript
详解webpack+express多页站点开发
2017/12/22 Javascript
jQuery事件多次绑定与解绑问题实例分析
2019/02/19 jQuery
vue的keep-alive用法技巧
2019/08/15 Javascript
vue用ant design中table表格,点击某行时触发的事件操作
2020/10/28 Javascript
Python中设置变量作为默认值时容易遇到的错误
2015/04/03 Python
总结python实现父类调用两种方法的不同
2017/01/15 Python
详解appium+python 启动一个app步骤
2017/12/20 Python
python flask中静态文件的管理方法
2018/03/20 Python
python如何将图片转换为字符图片
2020/08/19 Python
python求最大连续子数组的和
2018/07/07 Python
Python2.x与3​​.x版本有哪些区别
2020/07/09 Python
HTML5中外部浏览器唤起微信分享功能的代码
2020/09/15 HTML / CSS
美国韩国化妆品和护肤品购物网站:Beautytap
2018/07/29 全球购物
高中物理教学反思
2014/02/08 职场文书
南京南京观后感
2015/06/02 职场文书
Nginx开启Brotli压缩算法实现过程详解
2021/03/31 Servers
Python控制台输出俄罗斯方块移动和旋转功能
2021/04/18 Python
react如何快速设置文件路径别名
2021/04/28 Javascript
Window server中安装Redis的超详细教程
2021/11/17 Redis
python 远程执行命令的详细代码
2022/02/15 Python
Python+Selenium实现读取网易邮箱验证码
2022/03/13 Python