深入理解javascript作用域第二篇之词法作用域和动态作用域


Posted in Javascript onJuly 24, 2016

前面的话

大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找。再加上this机制的干扰,使得变量查找极易出错。这实际上是由两种作用域工作模型导致的,作用域分为词法作用域和动态作用域,分清这两种作用域模型就能够对变量查找过程有清晰的认识。本文是深入理解javascript作用域系列第二篇——词法作用域和动态作用域

词法作用域

第一篇介绍过,编译器的第一个工作阶段叫作分词,就是把由字符组成的字符串分解成词法单元。这个概念是理解词法作用域的基础

简单地说,词法作用域就是定义在词法阶段的作用域,是由写代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变

关系

无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定

function foo(a) {
var b = a * 2;
function bar(c) {
console.log( a, b, c );
}
bar(b * 3);
}
foo( 2 ); // 2 4 12

在这个例子中有三个逐级嵌套的作用域。为了帮助理解,可以将它们想象成几个逐级包含的气泡

作用域气泡由其对应的作用域块代码写在哪里决定,它们是逐级包含的

气泡1包含着整个全局作用域,其中只有一个标识符:foo

气泡2包含着foo所创建的作用域,其中有三个标识符:a、bar和b

气泡3包含着bar所创建的作用域,其中只有一个标识符:c

查找

作用域气泡的结构和互相之间的位置关系给引擎提供了足够的位置信息,引擎用这些信息来查找标识符的位置

在代码片段中,引擎执行console.log(...)声明,并查找a、b和c三个变量的引用。它首先从最内部的作用域,也就是bar(...)函数的作用域开始查找。引擎无法在这里找到a,因此会去上一级到所嵌套的foo(...)的作用域中继续查找。在这里找到了a,因此引擎使用了这个引用。对b来讲也一样。而对c来说,引擎在bar(...)中找到了它

[注意]词法作用域查找只会查找一级标识符,如果代码引用了foo.bar.baz,词法作用域查找只会试图查找foo标识符,找到这个变量后,对象属性访问规则分别接管对bar和baz属性的访问

foo = {
bar:{
baz: 1
}
};
console.log(foo.bar.baz);//1

遮蔽

作用域查找从运行时所处的最内部作用域开始,逐级向外或者说向上进行,直到遇见第一个匹配的标识符为止

在多层的嵌套作用域中可以定义同名的标识符,这叫作“遮蔽效应”,内部的标识符“遮蔽”了外部的标识符

var a = 0;
function test(){
var a = 1;
console.log(a);//1
}
test();

全局变量会自动为全局对象的属性,因此可以不直接通过全局对象的词法名称,而是间接地通过对全局对象属性的引用来对其进行访问

var a = 0;
function test(){
var a = 1;
console.log(window.a);//0
}
test();

通过这种技术可以访问那些被同名变量所遮蔽的全局变量。但非全局的变量如果被遮蔽了,无论如何都无法被访问到

动态作用域

javascript使用的是词法作用域,它的最重要的特征是它的定义过程发生在代码的书写阶段

那为什么要介绍动态作用域呢?实际上动态作用域是javascript另一个重要机制this的表亲。作用域混乱多数是因为词法作用域和this机制相混淆,傻傻分不清楚

动态作用域并不关心函数和作用域是如何声明以及在任何处声明的,只关心它们从何处调用。换句话说,作用域链是基于调用栈的,而不是代码中的作用域嵌套

var a = 2;
function foo() {
console.log( a );
}
function bar() {
var a = 3;
foo();
}
bar();

【1】如果处于词法作用域,也就是现在的javascript环境。变量a首先在foo()函数中查找,没有找到。于是顺着作用域链到全局作用域中查找,找到并赋值为2。所以控制台输出2

【2】如果处于动态作用域,同样地,变量a首先在foo()中查找,没有找到。这里会顺着调用栈在调用foo()函数的地方,也就是bar()函数中查找,找到并赋值为3。所以控制台输出3

小结:两种作用域的区别,简而言之,词法作用域是在定义时确定的,而动态作用域是在运行时确定的

以上所述是小编给大家介绍的深入理解javascript作用域第二篇之词法作用域和动态作用域,希望对大家有所帮助,如果大家想了解更多内容敬请关注三水点靠木!

Javascript 相关文章推荐
XENON基于JSON变种
Jul 27 Javascript
关于JavaScript中的关联数组分析
Apr 09 Javascript
公共js在页面底部加载的注意事项介绍
Jul 18 Javascript
javascript判断是手机还是电脑访问网页的简单实例分享
Jun 03 Javascript
JS仿淘宝实现的简单滑动门效果代码
Oct 14 Javascript
JavaScript实现打开链接页面的方式汇总
Jun 02 Javascript
JS控制文本域只读或可写属性的方法
Jun 24 Javascript
Bootstrap下拉菜单效果实例代码分享
Jun 30 Javascript
AngularJS获取json数据的方法详解
May 27 Javascript
用Vue-cli搭建的项目中引入css报错的原因分析
Jul 20 Javascript
Vue+Express实现登录注销功能的实例代码
May 05 Javascript
Vue scrollBehavior 滚动行为实现后退页面显示在上次浏览的位置
May 27 Javascript
关于input全选反选恶心的异常情况
Jul 24 #Javascript
JS中的==运算: [''] == false —>true
Jul 24 #Javascript
JavaScript关于提高网站性能的几点建议(一)
Jul 24 #Javascript
JavaScript提高网站性能优化的建议(二)
Jul 24 #Javascript
JavaScript学习小结之使用canvas画“哆啦A梦”时钟
Jul 24 #Javascript
省市二级联动小案例讲解
Jul 24 #Javascript
基于jQuery实现多标签页切换的效果(web前端开发)
Jul 24 #Javascript
You might like
使用php检测用户当前使用的浏览器是否为IE浏览器
2013/12/03 PHP
php获取bing每日壁纸示例分享
2014/02/25 PHP
php中删除数组的第一个元素和最后一个元素的函数
2015/03/07 PHP
JavaScript中Math对象使用说明
2008/01/16 Javascript
jquery 插件 web2.0分格的分页脚本,可用于ajax无刷新分页
2008/12/25 Javascript
js 鼠标点击事件及其它捕获
2009/06/04 Javascript
JavaScript 学习笔记二 字符串拼接
2010/03/28 Javascript
Node.js模拟浏览器文件上传示例
2014/03/26 Javascript
深入分析JSONP跨域的原理
2014/12/10 Javascript
jQuery在页面加载时动态修改图片尺寸的方法
2015/03/20 Javascript
JavaScript实现模仿桌面窗口的方法
2015/07/18 Javascript
JavaScript控制浏览器全屏及各种浏览器全屏模式的方法、属性和事件
2015/12/20 Javascript
原生JS封装Ajax插件(同域、jsonp跨域)
2016/05/03 Javascript
Bootstrap3 input输入框插入glyphicon图标的方法
2016/05/16 Javascript
详解nodejs微信公众号开发——1.接入微信公众号
2017/04/10 NodeJs
Node.js中的require.resolve方法使用简介
2017/04/23 Javascript
解决Vue2.x父组件与子组件之间的双向绑定问题
2018/03/06 Javascript
nodejs实现一个word文档解析器思路详解
2018/08/14 NodeJs
Vue传参一箩筐(页面、组件)
2019/04/04 Javascript
json解析大全 双引号、键值对不在一起的情况
2019/12/06 Javascript
Node Express用法详解【安装、使用、路由、中间件、模板引擎等】
2020/05/13 Javascript
你应该知道的python列表去重方法
2017/01/17 Python
Python实现PS图像调整黑白效果示例
2018/01/25 Python
浅谈python numpy中nonzero()的用法
2018/04/02 Python
Python基础知识点 初识Python.md
2019/05/14 Python
python3中利用filter函数输出小于某个数的所有回文数实例
2019/11/24 Python
python实现图像随机裁剪的示例代码
2020/12/10 Python
HTML5+css3:3D旋转木马效果相册
2017/01/03 HTML / CSS
详解canvas绘制多张图的排列顺序问题
2019/01/21 HTML / CSS
Silk Therapeutics官网:清洁、抗衰老护肤品
2020/08/12 全球购物
师范生实习个人的自我评价
2013/09/28 职场文书
会计与审计专业大专生求职信
2013/10/03 职场文书
护理助产毕业生的求职信
2014/03/02 职场文书
法人代表委托书
2014/04/04 职场文书
心理健康日活动总结
2014/05/08 职场文书
软弱涣散基层党组织整改方案
2014/10/25 职场文书