容易被忽略的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 相关文章推荐
JavaScript中的变量声明早于赋值分析
Mar 01 Javascript
Jquery图片滚动与幻灯片的实例代码
Apr 08 Javascript
jquery ajax方式直接提交整个表单核心代码
Aug 15 Javascript
JavaScript数据类型检测代码分享
Jan 26 Javascript
PHP+jQuery+Ajax+Mysql如何实现发表心情功能
Aug 06 Javascript
深入理解JavaScript中为什么string可以拥有方法
May 24 Javascript
JavaScript提升性能的常用技巧总结【经典】
Jun 20 Javascript
巧用weui.topTips验证数据的实例
Apr 17 Javascript
JavaScript实现前端实时搜索功能
Mar 26 Javascript
Vue.js中extend选项和delimiters选项的比较
Jul 17 Javascript
jQuery选择器之层次选择器用法实例分析
Feb 19 jQuery
JS实现多功能计算器
Oct 28 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
全国FM电台频率大全 - 19 广东省
2020/03/11 无线电
深入解析php中的foreach函数
2013/08/31 PHP
PHP采用curl模仿用户登陆新浪微博发微博的方法
2014/11/07 PHP
php实现事件监听与触发的方法
2014/11/21 PHP
Thinkphp5行为使用方法汇总
2017/12/21 PHP
使用laravel根据用户类型来显示或隐藏字段
2019/10/17 PHP
js自执行函数的几种不同写法的比较
2012/08/16 Javascript
treepanel动态加载数据实现代码
2012/12/15 Javascript
JS实现悬浮移动窗口(悬浮广告)的特效
2013/03/12 Javascript
js验证电话号码与手机支持+86的正则表达式
2014/01/23 Javascript
JQuery中使用on方法绑定hover事件实例
2014/12/09 Javascript
使用CamanJS在Web页面上处理图像的技巧
2015/08/18 Javascript
Vue.js开发环境搭建
2016/11/10 Javascript
原生js实现省市区三级联动代码分享
2018/02/12 Javascript
JavaScript中click和onclick本质区别与用法分析
2018/06/07 Javascript
Vue使用zTree插件封装树组件操作示例
2019/04/25 Javascript
vue实现瀑布流组件滑动加载更多
2020/03/10 Javascript
JavaScript日期库date-fn.js使用方法解析
2020/09/09 Javascript
vue 使用 v-model 双向绑定父子组件的值遇见的问题及解决方案
2021/03/01 Vue.js
[01:00:53]2018DOTA2亚洲邀请赛3月29日 小组赛B组 iG VS Secret
2018/03/30 DOTA
python环形单链表的约瑟夫问题详解
2018/09/27 Python
Python使用sax模块解析XML文件示例
2019/04/04 Python
springboot配置文件抽离 git管理统 配置中心详解
2019/09/02 Python
Python读入mnist二进制图像文件并显示实例
2020/04/24 Python
Python实现疫情地图可视化
2021/02/05 Python
Antler英国官网:购买安特丽行李箱、拉杆箱
2019/08/25 全球购物
日本化妆品植村秀俄罗斯官方网站:Shu Uemura俄罗斯
2020/02/01 全球购物
总经理驾驶员岗位职责
2013/12/04 职场文书
初中化学教学反思
2014/01/23 职场文书
2014年社区妇联工作总结
2014/12/02 职场文书
2015商场元旦促销活动策划方案
2014/12/09 职场文书
小学生成绩单评语
2014/12/31 职场文书
Python打包exe时各种异常处理方案总结
2021/05/18 Python
python 远程执行命令的详细代码
2022/02/15 Python
船舶调度指挥系统——助力智慧海事
2022/02/18 无线电
高并发下Redis如何保持数据一致性(避免读后写)
2022/03/18 Redis