容易被忽略的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 相关文章推荐
JS对象与JSON格式数据相互转换
Feb 20 Javascript
jQuery用unbind方法去掉hover事件及其他方法介绍
Mar 18 Javascript
javascript闭包入门示例
Apr 30 Javascript
JS实现在网页中弹出一个输入框的方法
Mar 03 Javascript
jquery彩色投票进度条简单实例演示
Jul 23 Javascript
jQuery简单实现提交数据出现loading进度条的方法
Mar 29 Javascript
Bootstrap每天必学之附加导航(Affix)插件
Apr 25 Javascript
vue中将网页打印成pdf实例代码
Jun 15 Javascript
jQuery之动画ajax事件(实例讲解)
Jul 18 jQuery
Vue-cli 使用json server在本地模拟请求数据的示例代码
Nov 02 Javascript
angular2实现统一的http请求头方法
Aug 13 Javascript
JavaScript实现简单计算器功能
Dec 19 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 程序员应该使用的10个组件
2009/10/31 PHP
php基于curl扩展制作跨平台的restfule 接口
2015/05/11 PHP
PHP+原生态ajax实现的省市联动功能详解
2017/08/15 PHP
yii框架redis结合php实现秒杀效果(实例代码)
2017/10/26 PHP
PHP二维数组分页2种实现方法解析
2020/07/09 PHP
常用简易JavaScript函数
2009/04/09 Javascript
jquery插件制作简单示例说明
2012/02/03 Javascript
javascript设计简单的秒表计时器
2020/09/05 Javascript
javascript瀑布流式图片懒加载实例解析与优化
2016/02/23 Javascript
jquery输入数字随机抽奖特效的简单实现代码
2016/06/10 Javascript
AngularJS深入探讨scope,继承结构,事件系统和生命周期
2016/11/02 Javascript
原生JS实现的放大镜特效示例【测试可用】
2018/12/08 Javascript
javascript canvas API内容整理
2020/02/16 Javascript
在Uni中使用Vue的EventBus总线机制操作
2020/07/31 Javascript
JavaScript如何实现防止重复的网络请求的示例
2021/01/28 Javascript
[02:50]【扭转乾坤,只此一招】DOTA2永雾林渊版本开启新篇章
2020/12/22 DOTA
为Python的Tornado框架配置使用Jinja2模板引擎的方法
2016/06/30 Python
Django中的CBV和FBV示例介绍
2018/02/25 Python
Pytest mark使用实例及原理解析
2020/02/22 Python
python实现用户名密码校验
2020/03/18 Python
Xadmin+rules实现多选行权限方式(级联效果)
2020/04/07 Python
selenium+headless chrome爬虫的实现示例
2021/01/08 Python
浅析canvas元素的html尺寸和css尺寸对元素视觉的影响
2019/07/22 HTML / CSS
欧洲第一中国智能手机和平板电脑网上商店:CECT-SHOP
2018/01/08 全球购物
为什么要有struct关键字
2012/05/08 面试题
介绍一下Linux内核的排队自旋锁
2014/08/27 面试题
创业大赛策划书
2014/03/01 职场文书
农林环境专业求职信
2014/03/13 职场文书
春节联欢会主持词
2014/03/24 职场文书
常务副总经理岗位职责
2014/04/12 职场文书
安装工程师岗位职责
2015/02/13 职场文书
2015年幼儿园保育工作总结
2015/05/12 职场文书
写给医护人员的一封感谢信
2019/09/16 职场文书
Django migrate报错的解决方案
2021/05/20 Python
MySQL系列之十一 日志记录
2021/07/02 MySQL
深入浅出讲解Java8函数式编程
2022/01/18 Java/Android