详解JS作用域(一)
一、什么是作用域
存储和访问变量,是任何一种编程语言最基本的功能之一,变量存在哪里?程序需要时如何找到它?这些问题需要一套良好的规则来规范,这套规则,就成为作用域。
二、编译原理
js通常归类为解释语言,但它其实是编译语言,和传统编译语言不同,它不是提前编译,编译结果也不能在分布式系统中进行移植。js引擎进行编译的步骤和传统的编译语言非常相似,传统编译语言,程序中的一段源码在执行之前会经历三个步骤,统称为“编译”。
2.1 分词/词法分析
这个过程会讲由字符组成的祖父穿分解成有意义的代码块。这些代码块叫词法单元。例如:var a=2;会分解成以下这些词法单元:
var、a、=、2、;
空格是否会被当做词法单元,取决于空格在这门语言中是否具有意义。
2.2 解析/词法分析
这个过程是将词法单元流转成一个由元素逐级嵌套所组成的代表了程序语法结构的树,这个树叫做抽象语法树(AST)。
var a=2; 的抽象语法数中可能会有一个叫做VariableDeclaration的顶级节点,接下来是一个叫做Identifier(它的值是a)的节点,以及一个叫做AssignmentExpression的子节点,AssignmentExpression节点有一个叫做NumericLiteral(它的值是2)的子节点。
2.3 代码生成
将AST转换成可执行代码的过程叫做代码生成,简单来说就是有某种方法可以讲var a=2 ;的AST转化成一组机器指令,用来创建一个叫做a的变量(包括分配内存等),并将一个值存在a中。
比起那些编译过程只要三个步骤的语言编译器,js引擎要复杂得多,例如,在语法分析和代码生成阶段有特定的步骤来对运行性能进行优化,包括对冗余元素进行优化等。简单来说,任何js代码片段在执行前都要进行编译(通常就在执行前),因此js编译器首先会对var a=2;这段程序进行编译,然后做好执行他的准备,并且通常马上就会执行它。
三、理解作用域
3.1 参与到var a=2;进行处理的过程中的演员们
引擎:从头到尾负责整个js程序的编译和执行过程
编译器:引擎的好朋友,负责词法分析以及代码生成等脏活累活。
作用域:引擎的另外一个朋友,负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。
3.2 对话
看看var a=2;的执行过程。
编译器首先会将这段代码分解成词法单元,然后将词法单元解析成一个树结构,但是当编译器进行代码生成时,他对这段程序的处理方式和预期的有所不同。可以合理地假设编译器所产生的代码能够用下面的伪代码进行概括:“为一个变量分配内存,将其命名为a,然后将值2保存在这个变量”,然而,这并不完全正确。
事实上编译器会进行如下处理:
遇到var a,编译器会询问作用域是否已经有一个该名称的变量存在于同一个作用域的集合中,如果是,编译器会忽略该声明,继续进行编译,否则他会要求作用域在当前作用域的集合中声明一个新的变量,命名为a。
接下来编译器会为引擎声称运行时所需的代码,这些代码备用处理a=2这个赋值操作。引擎运行时会首先询问作用域,在当前的作用域集合中是否存在一个叫做a的变量,如果是,引擎会使用这个变量,否则,引擎会继续查找变量。
如果引擎最终找到了a变量,就会将2赋值给它,否则引擎会举手示意抛出一个异常。
所以,变量的复制操作会执行两个动作,首先编译器会在当前作用域中声明一个变量(如果之前没有声明过),然后再运行时引擎会在作用域中查找这个变量,如果能够找到就会对他赋值。
3.3 编译器有话说
编译器在编译过程的第二步中生成了代码,引擎执行它时,会通过查找变量a来判断是否已声明过,查询的过程由作用域协助,但是引擎执行怎么样的查询,会影响最终的查询结果。
引擎为会a进行LHS查询,另外一个查询的类型叫做RHS。
当变量出现在赋值操作的左侧时,进行LHS查询,出现在右侧时进行RHS查询。
console.log(a); //对a的引用是一个RHS引用
a=2;//对a的引用是LHS引用
三、作用域嵌套
当一个块或者函数嵌套在另外一个块或者函数中时,就发生了作用域嵌套,在当前作用域中无法找到这个变量时,引擎就会在外层嵌套的作用域中继续找,直到找到该变量,或抵挡最外层的作用域位置。
function foo(a){
console.log(a+b);
}
var b=2;
foo(2);
引擎:foo作用域兄弟,你见过b吗?我需要对它进行RHS引用。
作用域:没有
引擎:foo的上级作用域兄弟,你见过b没?我需要对它进行RHS引用。
作用域:当然了,给你!
四、总结
作用域是一套规则,用于确定在何处以及如何查找变量,如果查找的目的是对变量赋值,那么就使用LHS查询,如果目的是获取变量的值,就用RHS查询,
详解JS作用域(一)的更多相关文章
- 详解js变量、作用域及内存
详解js变量.作用域及内存 来源:伯乐在线 作者:trigkit4 原文出处: trigkit4 基本类型值有:undefined,NUll,Boolean,Number和Strin ...
- 详解js和jquery里的this关键字
详解js和jquery里的this关键字 js中的this 我们要记住:this永远指向函数运行时所在的对象!而不是函数被创建时所在的对象.this对象是在运行时基于函数的执行环境绑定的,在全局环境中 ...
- [转]javascript console 函数详解 js开发调试的利器
javascript console 函数详解 js开发调试的利器 分步阅读 Console 是用于显示 JS和 DOM 对象信息的单独窗口.并且向 JS 中注入1个 console 对象,使用该 ...
- 详解js的bind、call、apply
详解js的bind.call.apply 说明 虽然bind.call.apply都是js很基础的一块知识,但是我从未认真总结过这三者的区别. 由于公司后端是用的微服务架构,又没有中间层对接,导致前端 ...
- 详解js面向对象编程
转自:http://segmentfault.com/a/1190000000713346 基本概念 ECMA关于对象的定义是:”无序属性的集合,其属性可以包含基本值.对象或者函数.“对象的每个属性或 ...
- 详解js中的闭包
前言 在js中,闭包是一个很重要又相当不容易完全理解的要点,网上关于讲解闭包的文章非常多,但是并不是非常容易读懂,在这里以<javascript高级程序设计>里面的理论为基础.用拆分的方式 ...
- Jquery 选择器 详解 js 判断字符串是否包含另外一个字符串
Jquery 选择器 详解 在线文档地址:http://tool.oschina.net/apidocs/apidoc?api=jquery 各种在线工具地址:http://www.ostools ...
- js详解之作用域-实例
函数如下大家可以做做看 function aa(a,b,c){ function a(){} console.log(a); console.log(aa); console.log(argument ...
- 详解JS设计模式
原文链接:www.cnblogs.com 一:理解工厂模式 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式. 简单的工厂模式可以理解为解决 ...
随机推荐
- 网络测试常用的命令-比较ping,tracert和pathping等命令之间的关系
无论你是一个网络维护人员,还是正在学习TCP/IP协议,了解和掌握一些常用的网络测试命令将会有助于您更快地检测到网络故障所在,同时也会有助你您了解网络通信的内幕. 下面我们逐步介绍几个常用的命令: 1 ...
- Redis集群与事务
redis集群对象JedisCluster不支持事务,但是,集群里面的每个节点支持事务 但是可以用第三方呀 启动下,然后看看事务问题: /usr/local/redis/bin/redis-serve ...
- MPEG学习
Mpeg:moving picture experts group 移动图片专家组 导入:Mpeg技术在我理解就是我们对音视频信息的一个输出标准.主要包括MPEG-1.MPEG-2.MPEG-4.MP ...
- Python: PS 图像特效 — 模糊玻璃
今天介绍一种基于高斯滤波和邻域随机采样,生成一种毛玻璃的图像特效,简单来说,就是先对图像做高斯滤波模糊,然后对模糊后的图像,通过对邻域的随机采样来赋予当前的像素点,这样,生成的图像有有一定的随机扰动和 ...
- TCPDUMP 使用详情
第一种是关于类型的关键字,主要包括host,net,port, 例如 host 210.27.48.2,指明 210.27.48.2是一台主机,net 202.0.0.0 指明 202.0.0.0是一 ...
- [Codeforces 787D] Legacy
[题目链接] https://codeforces.com/contest/787/problem/D [算法] 线段树优化建边 , 然后用Dijkstra算法求单源最短路 时间复杂度 : O((N ...
- [AH2017/HNOI2017]抛硬币
传送门 这个题的暴力比较好想--然后用一些组合的知识就可以变成正解了. 首先我们考虑a=b的情况.我们把扔出来的硬币看成是一个01序列,那么对于一个b获胜的序列,他在每一位都按位异或1之后必然是一个a ...
- PHP/Javascript 数组定义 及JSON中的使用 ---OK
PHP数组定义 一维数组: 1.$a=array(1,2,4,5,6); 2.$a= Array("cec"=>"cecValue","logo ...
- js格式
/** * Created by admin on 2017/9/22. */ // 分号后不要再有多余的空格 var name = "North"; var name = &qu ...
- 注销ie中的ActiveX插件
最新在C#下开发ActiveX控件,遇到一个问题,就是在调试的时候,ActiveX就已经注册在了调试目录下,这样即使安装这个插件,也无法注册到ActiveX的安装目录下.为了解决这个问题,需要注销下调 ...