容易被忽略的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 相关文章推荐
Google排名中的10个最著名的 JavaScript库
Apr 27 Javascript
jQuery Ajax使用 全解析
Dec 15 Javascript
jQuery获取Select选择的Text和Value(详细汇总)
Jan 25 Javascript
JavaScript通过元素的ID和name设置样式
Jul 08 Javascript
Javascript添加监听与删除监听用法详解
Dec 19 Javascript
jQuery实现可高亮显示的二级CSS菜单效果
Sep 01 Javascript
JS实现iframe自适应高度的方法示例
Jan 07 Javascript
JavaScript实现瀑布流以及加载效果
Feb 11 Javascript
AngularJS实现的base64编码与解码功能示例
May 17 Javascript
Vue实现数据表格合并列rowspan效果
Nov 30 Javascript
jQuery实现判断滚动条滚动到document底部的方法分析
Aug 27 jQuery
JS实现点击掉落特效
Jan 29 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扩展函数
2006/10/09 PHP
PHP用身份证号获取星座和生肖的方法
2013/11/07 PHP
php构造函数实例讲解
2013/11/13 PHP
PHP之sprintf函数用法详解
2014/11/12 PHP
php常见的魔术方法详解
2014/12/25 PHP
PHP分享图片的生成方法
2018/04/25 PHP
jQuery中需要注意的细节问题小结
2011/12/06 Javascript
Js动态添加复选框Checkbox的实例方法
2013/04/08 Javascript
javascript获取ckeditor编辑器的值(实现代码)
2013/11/18 Javascript
js正则表达exec与match的区别说明
2014/01/29 Javascript
jquery和js实现对div的隐藏和显示方法
2014/09/26 Javascript
vue2.0实战之使用vue-cli搭建项目(2)
2017/03/27 Javascript
使用vue-router设置每个页面的title方法
2018/02/11 Javascript
vue.js的computed,filter,get,set的用法及区别详解
2018/03/08 Javascript
vue组件实现弹出框点击显示隐藏效果
2020/10/26 Javascript
Vue 动态路由的实现及 Springsecurity 按钮级别的权限控制
2019/09/05 Javascript
node.JS二进制操作模块buffer对象使用方法详解
2020/02/06 Javascript
[03:48]DOTA2完美大师赛主赛事第二日精彩集锦
2017/11/24 DOTA
Python struct.unpack
2008/09/06 Python
wxPython中listbox用法实例详解
2015/06/01 Python
python利用高阶函数实现剪枝函数
2018/03/20 Python
在flask中使用python-dotenv+flask-cli自定义命令(推荐)
2020/01/05 Python
解决Pycharm的项目目录突然消失的问题
2020/01/20 Python
使用Tensorflow实现可视化中间层和卷积层
2020/01/24 Python
python GUI库图形界面开发之PyQt5切换按钮控件QPushButton详细使用方法与实例
2020/02/28 Python
使用OpenCV获取图像某点的颜色值,并设置某点的颜色
2020/06/02 Python
Furla官网:意大利著名的皮革品牌
2019/08/06 全球购物
犯错检讨书
2014/02/21 职场文书
环境建设实施方案
2014/03/14 职场文书
人代会标语
2014/06/30 职场文书
警察群众路线整改措施
2014/09/26 职场文书
校友会致辞
2015/07/30 职场文书
公文格式,规则明细(新手收藏)
2019/07/23 职场文书
Python+Appium新手教程
2021/04/17 Python
python-for x in range的用法(注意要点、细节)
2021/05/10 Python
微信小程序APP的事件绑定以及传递参数时的冒泡和捕获
2022/04/19 Javascript