容易被忽略的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 相关文章推荐
jsTree树控件(基于jQuery, 超强悍)[推荐]
Sep 01 Javascript
javascript 用原型继承来实现对象系统
Mar 22 Javascript
js中call与apply的用法小结
Dec 28 Javascript
把jQuery的类、插件封装成seajs的模块的方法
Mar 12 Javascript
jQuery仿天猫实现超炫的加入购物车
May 04 Javascript
配置Grunt的Task时通配符支持和动态生成文件名问题
Sep 06 Javascript
AngularJs  Understanding Angular Templates
Sep 02 Javascript
JavaScript 详解预编译原理
Jan 22 Javascript
js Dom实现换肤效果
Oct 21 Javascript
简单明了区分escape、encodeURI和encodeURIComponent
May 26 Javascript
vue中v-for循环给标签属性赋值的方法
Oct 18 Javascript
微信小程序自定义弹出模态框禁止底部滚动功能
Mar 09 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
php递归获取目录内文件(包含子目录)封装类分享
2013/12/25 PHP
深入理解PHP内核(二)之SAPI探究
2015/11/10 PHP
PHP实现JS中escape与unescape的方法
2016/07/11 PHP
Yii 实现数据加密和解密
2021/03/09 PHP
深入理解(function(){... })();
2016/08/16 Javascript
vue.js实现表格合并示例代码
2016/11/30 Javascript
浅谈ECMAScript6新特性之let、const
2017/08/02 Javascript
vue动态路由配置及路由传参的方式
2018/05/23 Javascript
Vue瀑布流插件的使用示例
2018/09/19 Javascript
微信小程序地图实现展示线路
2020/07/29 Javascript
实例讲解React 组件
2020/07/07 Javascript
[01:50]WODOTA制作 DOTA2中文宣传片《HERO》
2013/04/28 DOTA
Python Mysql自动备份脚本
2008/07/14 Python
python 文件与目录操作
2008/12/24 Python
python 中文字符串的处理实现代码
2009/10/25 Python
简单的Python的curses库使用教程
2015/04/11 Python
Python+Socket实现基于UDP协议的局域网广播功能示例
2017/08/31 Python
Python装饰器用法实例总结
2018/02/07 Python
Python从零开始创建区块链
2018/03/06 Python
关于django 数据库迁移(migrate)应该知道的一些事
2018/05/27 Python
java判断三位数的实例讲解
2019/06/10 Python
Python面向对象编程基础实例分析
2020/01/17 Python
Python开发入门——迭代的基本使用
2020/09/03 Python
python中random模块详解
2021/03/01 Python
HTML5新增form控件和表单属性实例代码详解
2019/05/15 HTML / CSS
澳大利亚冒险体验:Adrenaline(跳伞、V8赛车、热气球等)
2017/09/18 全球购物
ALDO加拿大官网:加拿大女鞋品牌
2018/12/22 全球购物
日本高岛屋百货购物网站:TAKASHIMAYA
2019/03/24 全球购物
澳大利亚礼品篮网站:Macarthur Baskets
2019/10/14 全球购物
转党组织关系介绍信
2014/01/08 职场文书
2014国庆节主题活动方案:快乐的国庆节
2014/09/16 职场文书
运动会广播稿200字
2014/10/18 职场文书
开展党的群众路线教育实践活动情况汇报
2014/11/05 职场文书
2016年春季趣味运动会开幕词
2016/03/04 职场文书
小学四年级作文之最感动的一件事
2019/11/01 职场文书
python读取并查看npz/npy文件数据以及数据显示方法
2022/04/14 Python