容易被忽略的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 实现checkbox全选,反选,全不选等功能代码(奇数)
Oct 24 Javascript
jQuery setTimeout()函数使用方法
Apr 07 Javascript
在父页面调用子页面的JS方法
Sep 29 Javascript
php is_numberic函数造成的SQL注入漏洞
Mar 10 Javascript
js闭包的用途详解
Nov 09 Javascript
node.js cookie-parser 中间件介绍
Jun 06 Javascript
使用JavaScript实现一个小程序之99乘法表
Sep 21 Javascript
详解Vue项目编译后部署在非网站根目录的解决方案
Apr 26 Javascript
jQuery轻量级表单模型验证插件
Oct 15 jQuery
vue.config.js中配置Vue的路径别名的方法
Feb 11 Javascript
layui实现显示数据表格、搜索和修改功能示例
Jun 03 Javascript
使用next.js开发网址缩短服务的方法
Jun 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代码
2013/03/24 PHP
探讨fckeditor在Php中的配置详解
2013/06/08 PHP
php命令行(cli)模式下报require 加载路径错误的解决方法
2015/11/23 PHP
php观察者模式应用场景实例详解
2017/02/03 PHP
php实现生成PDF文件的方法示例【基于FPDF类库】
2018/07/21 PHP
取得一定长度的内容,处理中文
2006/12/20 Javascript
拖动Html元素集合 Drag and Drop any item
2006/12/22 Javascript
javascript vvorld 在线加密破解方法
2008/11/13 Javascript
写入cookie的JavaScript代码库 cookieLibrary.js
2009/10/24 Javascript
简单实例处理url特殊符号&处理(2种方法)
2013/04/02 Javascript
jquery fancybox ie6不显示关闭按钮的解决办法
2013/12/25 Javascript
JS替换文本域内的回车示例
2014/02/18 Javascript
AngularJS入门知识之MVW类框架的编程思想探讨
2014/12/08 Javascript
jQuery中size()方法用法实例
2014/12/27 Javascript
jQuery实现将页面上HTML标签换成另外标签的方法
2015/06/09 Javascript
AngularJS 实现点击按钮获取验证码功能实例代码
2017/07/13 Javascript
bootstrap treeview 扩展addNode方法动态添加子节点的方法
2017/11/21 Javascript
vue-cli3 项目从搭建优化到docker部署的方法
2019/01/28 Javascript
微信小程序如何通过用户授权获取手机号(getPhoneNumber)
2020/01/21 Javascript
Vue 中使用 typescript的方法详解
2020/02/17 Javascript
在Python中用keys()方法返回字典键的教程
2015/05/21 Python
Python OS模块常用函数说明
2015/05/23 Python
基于python实现学生信息管理系统
2019/11/22 Python
python求解汉诺塔游戏
2020/07/09 Python
Python通过format函数格式化显示值
2020/10/17 Python
德国低价购买灯具和家具网站:Style-home.de
2016/11/25 全球购物
Paradox London官方网站:英国新娘鞋婚礼鞋品牌
2019/08/29 全球购物
英国领先的在线礼品店:Getting Personal
2019/09/24 全球购物
2014学校庆三八妇女节活动总结
2014/03/01 职场文书
股东合作协议书
2014/04/14 职场文书
勾股定理课后反思
2014/04/26 职场文书
公司食堂管理制度
2015/08/05 职场文书
python爬取新闻门户网站的示例
2021/04/25 Python
详解分布式系统中如何用python实现Paxos
2021/05/18 Python
GTX1650super好不好 gtx1650super显卡属于什么级别
2022/04/08 数码科技
mysql查看表结构的三种方法总结
2022/07/07 MySQL