【转】深入理解javascript作用域——词法作用域和动态作用域
前面的话
大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找。再加上this机制的干扰,使得变量查找极易出错。这实际上是由两种作用域工作模型导致的,作用域分为词法作用域和动态作用域,分清这两种作用域模型就能够对变量查找过程有清晰的认识。本文是深入理解javascript作用域系列第二篇——词法作用域和动态作用域
词法作用域
第一篇介绍过,编译器的第一个工作阶段叫作分词,就是把由字符组成的字符串分解成词法单元。这个概念是理解词法作用域的基础
简单地说,词法作用域就是定义在词法阶段的作用域,是由写代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变
关系
无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定
|
1
2
3
4
5
6
7
8
|
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属性的访问
|
1
2
3
4
5
6
|
foo = {bar:{baz: 1}};console.log(foo.bar.baz);//1 |
遮蔽
作用域查找从运行时所处的最内部作用域开始,逐级向外或者说向上进行,直到遇见第一个匹配的标识符为止
在多层的嵌套作用域中可以定义同名的标识符,这叫作“遮蔽效应”,内部的标识符“遮蔽”了外部的标识符
|
1
2
3
4
5
6
|
var a = 0;function test(){var a = 1;console.log(a);//1}test(); |
全局变量会自动为全局对象的属性,因此可以不直接通过全局对象的词法名称,而是间接地通过对全局对象属性的引用来对其进行访问
|
1
2
3
4
5
6
|
var a = 0;function test(){var a = 1;console.log(window.a);//0}test(); |
通过这种技术可以访问那些被同名变量所遮蔽的全局变量。但非全局的变量如果被遮蔽了,无论如何都无法被访问到
动态作用域
javascript使用的是词法作用域,它的最重要的特征是它的定义过程发生在代码的书写阶段
那为什么要介绍动态作用域呢?实际上动态作用域是javascript另一个重要机制this的表亲。作用域混乱多数是因为词法作用域和this机制相混淆,傻傻分不清楚
动态作用域并不关心函数和作用域是如何声明以及在任何处声明的,只关心它们从何处调用。换句话说,作用域链是基于调用栈的,而不是代码中的作用域嵌套
|
1
2
3
4
5
6
7
8
9
|
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系列(14):作用域链(Scope Chain)
前言 在第12章关于变量对象的描述中,我们已经知道一个执行上下文 的数据(变量.函数声明和函数的形参)作为属性存储在变量对象中. 同时我们也知道变量对象在每次进入上下文时创建,并填入初始值,值的更新出 ...
- 深入理解javascript作用域系列第二篇——词法作用域和动态作用域
× 目录 [1]词法 [2]动态 前面的话 大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找.再加上this机制的干扰,使得变量查找极 ...
- 深入理解javascript作用域系列第二篇
前面的话 大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找.再加上this机制的干扰,使得变量查找极易出错.这实际上是由两种作用域工作 ...
- JavaScript深入之词法作用域和动态作用域
作用域 作用域是指程序源代码中定义变量的区域. 作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限. JavaScript 采用词法作用域,也就是静态作用域. 静态作用域与动态作用域 因 ...
- Javascript中的词法作用域、动态作用域、函数作用域和块作用域(四)
一.js中的词法作用域和动态作用域 词法作用域也就是在词法阶段定义的作用域,也就是说词法作用域在代码书写时就已经确定了. js中其实只有词法作用域,并没有动态作用域,this的执 ...
- 前端知识体系:JavaScript基础-作用域和闭包-词法作用域和动态作用域
词法作用域和动态作用域 1.作用域: 作用域是指程序代码中定义变量的区域 JavaScript采用词法作用域,也就是静态作用域 2.词法作用域和动态作用域 因为JavaScript采用的是词法作用域, ...
- JavaScript深入之词法作用域和动态作用域(转载)
作用域 作用域是指程序源代码中定义变量的区域. 作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限. JavaScript 采用词法作用域(lexical scoping),也就是静态作 ...
- 深入学习js之——词法作用域和动态作用域
开篇 当我们在开始学习任何一门语言的时候,都会接触到变量的概念,变量的出现其实是为了解决一个问题,为的是存储某些值,进而,存储某些值的目的是为了在之后对这个值进行访问或者修改,正是这种存储和访问变量的 ...
- 【作用域】词法作用域(静态作用域,如:js)、动态作用域(如:.bash脚本)
作用域 作用域是指程序源代码中定义变量的区域. 作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限. JavaScript 采用词法作用域(lexical scoping),也就是静态作 ...
随机推荐
- Log4net快速搭建
nuget安装log4net 2018.12.10当前版本为2.0.8 找到所在项目的[Properties->AssemblyInfo] 在底部加上 [assembly: log4net.Co ...
- Android(java)学习笔记193:ContentProvider使用之获得系统联系人信息01
1.系统联系人的数据库(3张最重要的表) (1)raw_contacts 联系人表 保存联系人的id contact_id (2)data 数据表 保存联系人的数据 ( ...
- zuul 网关
1.网关的作用 网关可以拦截客户端所有请求,对该请求进行权限控制,负载均衡.日志管理.接口调用监控等操作. 1)网关对所有服务会话进行拦截 2)网关安全控制,统一异常处理,XXS.SQL注入 3)权限 ...
- 【原】简单shell练习(三)
1.软链 linux下的软链接类似于windows下的快捷方式 # ln -s /home/gamestat /gamestat ln -s a b 中的 a 就是源文件(已经存在的文件),b是链 ...
- 从C#程序中调用非受管DLLs
从C#程序中调用非受管DLLs 文章概要: 众所周知,.NET已经渐渐成为一种技术时尚,那么C#很自然也成为一种编程时尚.如何利用浩如烟海的Win32 API以及以前所编写的 Win32 代码已经成为 ...
- svn in xcode5
两种办法,一是使用比较成熟的svn客户端,二是使用终端.以下为终端方法: 假设已经通过Xcode->Preferences->Accounts将repository: http://mys ...
- (3)Gojs model简介
(3)Gojs model简介 在GoJS中,model用来存储表的基本数据,包括node.link等具体对象和属性,与其在视觉上的展示效果不相关.model中往往只保存相对简单的数据,最方便且持久化 ...
- [HNOI/AHOI2018]转盘(线段树优化单调)
gugu bz lei了lei了,事独流体毒瘤题 一句话题意:任选一个点开始,每个时刻向前走一步或者站着不动 问实现每一个点都在$T_i$之后被访问到的最短时间 Step 1 该题可证: 最优方案必 ...
- js 技巧 (六)JavaScript[对象.属性]集锦
JavaScript[对象.属性]集锦 SCRIPT 标记 用于包含javascript代码. 语法 属性 LANGUAGE 定义脚本语言 SRC 定义一个URL用以指定以.JS结尾的文件 windo ...
- 20Spring切面的优先级
通过使用@order注解指定切面的优先级,值越小,优先级越高代码: package com.cn.spring.aop.impl; //加减乘除的接口类 public interface Arithm ...