详解js的作用域、预解析机制


Posted in Javascript onFebruary 05, 2018

虽然,ES6在我们工作中应用得越来越广泛,但是还是很多项目保留着ES5的写法,所以,今天,带着大家重新巩固下ES5下的作用域及预解析机制。

概念:

作用域:域,指的是一个空间、范围、区域,作用指的是在域内可进行读写操作。一个变量的作用域是程序源代码中定义的这个变量的区域。

在ES5中,只存在全局和函数级作用域,在ES6中,引入了块级作用域,js的预解析机制大概分为两个过程:预解析和自上而下逐行解读

预解析:js解析器会先把var定义的变量、function、参数等一些东西存储进仓库里面(内存)。变量var在正式运行之前,都赋值为undefined,function函数在运行之前,就是整个函数块

逐行解读

表达式=、+、-、*、/、++、--、!、%.....number()、参数都可以赋值

遇到重名的,只留下一个,变量和函数重名,函数优先级高于变量,只留下函数

函数调用(函数是一个作用域,遇到作用域都会按照先进行预解析,然后逐行解读的过程执行),先局部找参数,局部找不到就自下向上找(作用域链)

概念扯了一大段,估计初学者还是有点晕乎乎,老司机就可以提前下车了,接下来,咋们举几个小栗子,结合上面的理论,深入理解。

实践

例1:

alert(a); //error: a is not defined
a = 3;

分析:

预解析

上面说过,预解析时只会把var 、 function 、参数等存储起来,所以:

整个作用域没有找到var function 参数

逐行解读

预解析后,内存中存在a且被赋值了underfind整个变量,所有,代码执行过程中程序直接报错。

例2:

alert(a); //undefined
var a = 3;

分析:

预解析

上面说过,预解析时只会把var 、 function 、参数等存储起来,所以:

执行到第二行时,a 的值是未定义。

逐行解读

第一行:预解析后,内存中存在a且被赋值了underfined

例3:

alert(a);          // function a (){ alert(4); }
var a = 1;
alert(a);          // 1
function a (){ alert(2); }
alert(a);          // 1
var a = 3;    
alert(a);          // 3
function a (){ alert(4); }
alert(a);          // 3

分析:

域解析

上面说过,预解析时只会把var 、 function 、参数等存储起来,所以:

执行到第二行时,a 的值是未定义。

执行到第四行时,a 的值是函数本身,也就是function a(){alert(2);}。

执行到第六行时,a 的值还是第四行时的值,也就是function a(){alert(2);},因为函数的优先级比变量高。

执行到第八行时,a 的值就变成了function a(){alert(4);} ,因为当两个函数重名时,遵循代码从上往下执行。

逐行解读

预解析完成之后,就是代码逐行执行了,

第一行:会弹出function a(){alert(4);} ,因为预解析完成之后,被存进内存的a 的值就是function a(){alert(4);}

第二行:第二行里有表达式,a 被赋了一个新的值1 表达式会改变变量的值。表达式可以改变预解析的值。

第三行:a现在被赋值为1,所有会弹出1

第四行:只是函数的声明,并没有用到表达式,而且也没有函数的调用,所以不会改变a 的值。

第五行:因为a的值没有变化,所以还是1

第六行:使用了表达式,a 被赋了一个新的值3

第七行:会弹出3

第八行:函数的声明,不会改变a 的值。

第九行:a的值没有改变,所以还是3

通过上面的栗子,相信大家应该对变量作用域的预解析过程有一定的了解了,接下来,咋们再举几个函数作用域的栗子

例4:

var a=1;
function fn1(){
  alert(a); //undefined
  var a = 2;
}
fn1();
alert(a) //1

例5:

var a=1;
function fn1(a){
  alert(a); //1
  var a = 2;
}
fn1(a);
alert(a) //1

例6:

var a=1;
function fn1(a){
  alert(a); //1
  a = 2;
}
fn1(a);
alert(a) //1

例7:

var a=1;
function fn1(){
  alert(a); //1
  a = 2;
}
fn1(a);
alert(a) //2

这几个栗子想必不用在一步步分析吧,不过就一点小改动,可能结果就截然不同,所以,大家还是需要仔细琢磨下。

Javascript 相关文章推荐
ajaxControlToolkit AutoCompleteExtender的用法
Oct 30 Javascript
jQuery 顺便学习下CSS选择器 奇偶匹配nth-child(even)
May 24 Javascript
手机开发必备技巧:javascript及CSS功能代码分享
May 25 Javascript
js实现拖拽效果(构造函数)
Dec 14 Javascript
解决jQuery上传插件Uploadify出现Http Error 302错误的方法
Dec 18 Javascript
javascript获取select标签选中的值
Jun 04 Javascript
JS判断来路是否是百度等搜索索引进行弹窗或自动跳转的实现代码
Oct 09 Javascript
基于Vue实现页面切换左右滑动效果
Jun 29 Javascript
jQuery实现的form转json经典示例
Oct 10 jQuery
webpack多入口文件页面打包配置详解
Jan 09 Javascript
vue 2.0 购物车小球抛物线的示例代码
Feb 01 Javascript
一文了解vue-router之hash模式和history模式
May 31 Javascript
Vue使用枚举类型实现HTML下拉框步骤详解
Feb 05 #Javascript
jQuery实现动态显示select下拉列表数据的方法
Feb 05 #jQuery
详解vue静态资源打包中的坑与解决方案
Feb 05 #Javascript
理解Koa2中的async&await的用法
Feb 05 #Javascript
zTree 树插件实现全国五级地区点击后加载的示例
Feb 05 #Javascript
使用vue如何构建一个自动建站项目
Feb 05 #Javascript
在 webpack 中使用 ECharts的实例详解
Feb 05 #Javascript
You might like
日本收入最高的漫画家:海贼王作者版税年收入高达8.45亿元
2020/03/04 日漫
PHP Ajax实现页面无刷新发表评论
2007/01/02 PHP
修改php.ini实现Mysql导入数据库文件最大限制的修改方法
2007/12/11 PHP
浅谈discuz密码加密的方式
2014/05/22 PHP
PHP获取MySql新增记录ID值的3种方法
2014/06/24 PHP
PHP解析目录路径的3个函数总结
2014/11/18 PHP
php把大写命名转换成下划线分割命名
2015/04/27 PHP
php正则表达式基本知识与应用详解【经典教程】
2017/04/17 PHP
myEvent.js javascript跨浏览器事件框架
2011/10/24 Javascript
JavaScript将当前时间转换成UTC标准时间的方法
2015/04/06 Javascript
jQuery实现div横向拖拽排序的简单实例
2016/07/13 Javascript
JavaScript中使用参数个数实现重载功能
2017/09/01 Javascript
vue通过路由实现页面刷新的方法
2018/01/25 Javascript
vue.js中created方法作用
2018/03/30 Javascript
vue-cli2.9.3 详细教程
2018/04/23 Javascript
支付宝小程序自定义弹窗dialog插件的实现代码
2018/11/30 Javascript
java和js实现的洗牌小程序
2019/09/30 Javascript
jQuery 查找元素操作实例小结
2019/10/02 jQuery
[01:07:20]DOTA2-DPC中国联赛 正赛 Dynasty vs XG BO3 第二场 2月2日
2021/03/11 DOTA
利用Django框架中select_related和prefetch_related函数对数据库查询优化
2015/04/01 Python
python类的继承实例详解
2017/03/30 Python
python 数字类型和字符串类型的相互转换实例
2018/07/17 Python
解决pyttsx3无法封装的问题
2018/12/24 Python
Pyqt QImage 与 np array 转换方法
2019/06/27 Python
python开发实例之Python的Twisted框架中Deferred对象的详细用法与实例
2020/03/19 Python
python 读取二进制 显示图片案例
2020/04/24 Python
Python如何转换字符串大小写
2020/06/04 Python
python 绘制正态曲线的示例
2020/09/24 Python
德国购买健身器材:AsVIVA
2017/08/09 全球购物
英国鹦鹉店:Parrot Essentials
2018/12/03 全球购物
全球性的在线鞋类品牌:Public Desire
2019/04/03 全球购物
2015年乡镇卫生院工作总结
2015/04/22 职场文书
导盲犬小Q观后感
2015/06/11 职场文书
SpringBoot集成Redis,并自定义对象序列化操作
2021/06/22 Java/Android
Dubbo+zookeeper搭配分布式服务的过程详解
2022/04/03 Java/Android
Golang连接并操作MySQL
2022/04/14 MySQL