容易被忽略的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代码
Nov 23 Javascript
12个非常有创意的JavaScript小游戏
Mar 18 Javascript
删除javascript中注释语句的正则表达式
Jun 11 Javascript
Jquery对select的增、删、改、查操作
Feb 06 Javascript
JAVASCRIPT代码编写俄罗斯方块网页版
Nov 26 Javascript
jQuery 实现评论等级好评差评特效
May 06 Javascript
AngularJS基础 ng-list 指令详解及示例代码
Aug 02 Javascript
footer定位页面底部(代码分享)
Mar 07 Javascript
js实现倒计时器自定义时间和暂停
Feb 25 Javascript
Webpack4+Babel7+ES6兼容IE8的实现
Apr 10 Javascript
详解JWT token心得与使用实例
Aug 02 Javascript
vue 点击其他区域关闭自定义div操作
Jul 17 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数组查找函数总结
2014/11/18 PHP
utf8的编码算法 转载
2006/12/27 Javascript
asp.net网站开发中用jquery实现滚动浏览器滚动条加载数据(类似于腾讯微博)
2012/03/14 Javascript
基于JavaScript 数据类型之Boolean类型分析介绍
2013/04/19 Javascript
5秒后跳转到另一个页面的js代码
2013/10/12 Javascript
使用POST方式弹出窗口的两种方法示例介绍
2014/01/29 Javascript
css结合js制作下拉菜单示例代码
2014/02/27 Javascript
JS来动态的修改url实现对url的增删查改
2014/09/05 Javascript
JQuery插件Quicksand实现超炫的动画洗牌效果
2015/05/03 Javascript
异步JS框架的作用以及实现方法
2015/10/29 Javascript
基于javascript实现图片左右切换效果
2016/01/25 Javascript
ros::spin() 和 ros::spinOnce()函数的区别及详解
2016/10/01 Javascript
JS 滚动事件window.onscroll与position:fixed写兼容IE6的回到顶部组件
2016/10/10 Javascript
详解Vuejs2.0 如何利用proxyTable实现跨域请求
2017/08/03 Javascript
加载 vue 远程代码的组件实例详解
2017/11/20 Javascript
详解如何在vscode里面调试js和node.js的方法步骤
2018/12/24 Javascript
基于elementUI使用v-model实现经纬度输入的vue组件
2019/05/12 Javascript
手把手带你搭建一个node cli的方法示例
2020/08/07 Javascript
python根据给定文件返回文件名和扩展名的方法
2015/03/27 Python
python使用opencv驱动摄像头的方法
2018/08/03 Python
Django结合ajax进行页面实时更新的例子
2019/08/12 Python
如何基于python操作excel并获取内容
2019/12/24 Python
Python 实现向word(docx)中输出
2020/02/13 Python
python中resample函数实现重采样和降采样代码
2020/02/25 Python
python为什么会环境变量设置不成功
2020/06/23 Python
python用Configobj模块读取配置文件
2020/09/26 Python
CSS 3.0文字悬停跳动特效代码
2020/10/26 HTML / CSS
美国二手复古奢侈品包包购物网站:LXRandCo
2019/06/18 全球购物
全球最大的瓷器、水晶和银器零售商:Replacements
2020/06/15 全球购物
JSF如何进行表格处理及取值
2012/08/06 面试题
高级Java程序员面试题
2016/06/23 面试题
实习销售业务员自我鉴定
2013/09/21 职场文书
中学生爱国演讲稿
2013/12/31 职场文书
小摄影师教学反思
2014/04/27 职场文书
三好学生个人先进事迹材料
2014/05/17 职场文书
Nginx域名转发使用场景代码实例
2021/03/31 Servers