容易被忽略的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 Cookie的读取和写入函数
Dec 08 Javascript
判断目标是否是window,document,和拥有tagName的Element的代码
May 31 Javascript
关于scrollLeft,scrollTop的浏览器兼容性测试
Mar 19 Javascript
js实现日历可获得指定日期周数及星期几示例分享(js获取星期几)
Mar 14 Javascript
jQuery中data()方法用法实例
Dec 27 Javascript
BOOTSTRAP时间控件显示在模态框下面的bug修复
Feb 05 Javascript
动态加载jQuery的方法
Jun 16 Javascript
举例讲解JavaScript中关于对象操作的相关知识
Nov 16 Javascript
JS中解决谷歌浏览器记住密码输入框颜色改变功能
Feb 13 Javascript
node操作mysql数据库实例详解
Mar 17 Javascript
HTML的select控件美化
Mar 27 Javascript
从对象列表中获取一个对象的方法,依据关键字和值
Sep 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
使用eAccelerator加密PHP程序
2008/10/03 PHP
CodeIgniter采用config控制的多语言实现根据浏览器语言自动转换功能
2014/07/18 PHP
thinkphp3.0输出重复两次的解决方法
2014/12/19 PHP
smarty内置函数section的用法
2015/01/22 PHP
JSON两种结构之对象和数组的理解
2016/07/19 PHP
php集成动态口令认证
2016/07/21 PHP
PHP自定义函数获取汉字首字母的方法
2016/12/01 PHP
浅谈Laravel中的三种中间件的作用
2019/10/13 PHP
php连接mysql之mysql_connect()与mysqli_connect()的区别
2020/07/19 PHP
JavaScript表单常用验证集合
2008/01/16 Javascript
Jquery 选中表格一列并对表格排序实现原理
2012/12/15 Javascript
利用原生JavaScript获取元素样式只是获取而已
2014/10/08 Javascript
小程序表单认证布局及验证详解
2020/06/19 Javascript
Vue 解决通过this.$refs来获取DOM或者组件报错问题
2020/07/28 Javascript
vue-cli+webpack项目打包到服务器后,ttf字体找不到的解决操作
2020/08/28 Javascript
python开发中module模块用法实例分析
2015/11/12 Python
Python的string模块中的Template类字符串模板用法
2016/06/27 Python
Python打包可执行文件的方法详解
2016/09/19 Python
Python 25行代码实现的RSA算法详解
2018/04/10 Python
python获取命令行输入参数列表的实例代码
2018/06/23 Python
解决python3捕获cx_oracle抛出的异常错误问题
2018/10/18 Python
多个python文件调用logging模块报错误
2020/02/12 Python
python实现录音功能(可随时停止录音)
2020/10/26 Python
Django自带用户认证系统使用方法解析
2020/11/12 Python
如何基于Python和Flask编写Prometheus监控
2020/11/25 Python
使用python操作lmdb对数据读取的实例
2020/12/11 Python
anaconda升级sklearn版本的实现方法
2021/02/22 Python
阿根廷网上配眼镜:SmartBuyGlasses阿根廷
2016/08/19 全球购物
泰坦健身器材:Titan Fitness
2018/02/13 全球购物
土木工程师岗位职责
2013/11/24 职场文书
小露珠教学反思
2014/04/30 职场文书
计算机网络专业求职信
2014/06/05 职场文书
公司新人试用期自我评价
2014/09/17 职场文书
2014年评职称工作总结
2014/11/20 职场文书
离婚协议书范本(通用篇)
2014/11/30 职场文书
部门经理助理岗位职责
2015/04/13 职场文书