容易被忽略的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 相关文章推荐
JQuery自适应IFrame高度(支持嵌套 兼容IE,ff,safafi,chrome)
Mar 28 Javascript
javascript 函数声明与函数表达式的区别介绍
Oct 05 Javascript
JavaScript的React框架中的JSX语法学习入门教程
Mar 05 Javascript
AngularJS通过ng-Img-Crop实现头像截取的示例
Aug 17 Javascript
微信小程序实现action-sheet弹出底部菜单功能【附源码下载】
Dec 09 Javascript
ionic3实战教程之随机布局瀑布流的实现方法
Dec 28 Javascript
在 Linux/Unix 中不重启 Vim 而重新加载 .vimrc 文件的流程
Mar 21 Javascript
Angular4 反向代理Details实践
May 30 Javascript
js拖动滑块和点击水波纹效果实例代码
Oct 16 Javascript
微信小程序实现跑马灯效果
Oct 21 Javascript
element-ui 文件上传修改文件名的方法示例
Nov 05 Javascript
如何在vue中使用video.js播放m3u8格式的视频
Feb 01 Vue.js
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中http_build_query 的一个问题
2012/03/25 PHP
Thinkphp中的volist标签用法简介
2014/06/18 PHP
PHP生成数组再传给js的方法
2014/08/07 PHP
PHP原生函数一定好吗?
2014/12/08 PHP
PHP实现类似于C语言的文件读取及解析功能
2017/09/01 PHP
PHP命名空间(namespace)原理与用法详解
2019/12/11 PHP
js form action动态修改方法
2008/11/04 Javascript
js运动框架_包括图片的淡入淡出效果
2013/05/11 Javascript
第十章之巨幕页头缩略图与警告框组件
2016/04/25 Javascript
jquery动态切换背景图片的简单实现方法
2016/05/14 Javascript
模板视图和AngularJS之间冲突的解决方法
2016/11/22 Javascript
Node.js制作简单聊天室
2017/01/12 Javascript
JQuery中Ajax的操作完整例子
2017/03/07 Javascript
Angular.js中处理页面闪烁的方法详解
2017/03/09 Javascript
vuejs使用递归组件实现树形目录的方法
2017/09/30 Javascript
jquery一键控制checkbox全选、反选或全不选
2017/10/16 jQuery
原生JS写Ajax的请求函数功能
2017/12/22 Javascript
vue 的点击事件获取当前点击的元素方法
2018/09/15 Javascript
vue项目创建步骤及路由router
2020/01/14 Javascript
bootstrap-paginator服务器端分页使用方法详解
2020/02/13 Javascript
微信小程序实现文件预览
2020/10/22 Javascript
ajax jquery实现页面某一个div的刷新效果
2021/03/04 jQuery
详解利用OpenCV提取图像中的矩形区域(PPT屏幕等)
2019/07/01 Python
python try except返回异常的信息字符串代码实例
2019/08/15 Python
Django Admin中增加导出CSV功能过程解析
2019/09/04 Python
在Python中使用MySQL--PyMySQL的基本使用方法
2019/11/19 Python
python字符串常用方法及文件简单读写的操作方法
2020/03/04 Python
基于Pytorch版yolov5的滑块验证码破解思路详解
2021/02/25 Python
教育学专业毕业生的自我鉴定
2013/11/26 职场文书
租房协议书范本
2014/04/09 职场文书
创优争先心得体会
2014/09/11 职场文书
国家领导干部党的群众路线教育实践活动批评与自我批评材料
2014/09/23 职场文书
期末考试复习计划
2015/01/19 职场文书
nginx 反向代理之 proxy_pass的实现
2021/03/31 Servers
PyCharm 安装与使用配置教程(windows,mac通用)
2021/05/12 Python
Mysql的Table doesn't exist问题及解决
2022/12/24 MySQL