详解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 一:理解工厂模式 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式. 简单的工厂模式可以理解为解决 ...
随机推荐
- ffmpeg视频格式转换中关键帧的设置
在用ffmpeg转换视频到flv过程中,需要设置关键帧的间隔,以便在播放过程中实现精确定位.在网上查找了不少,最后发现这个指令有效: -g 1 -keyint_min 2 . http://blog. ...
- html5--5-14 阶段小练习:绘制太极图案
html5--5-14 阶段小练习:绘制太极图案 学习要点 运用前几节课的知识完成一个小练习 这个图案有多种不同的绘制方法,这里只做一个简单的演示,练习的时候可以自己思考一下,尝试其他的方法,或者对这 ...
- hadoop源码剖析--RawLocalFileSystem
RawLocalFileSystem是hadoop中实现的本地文件系统,在该类中与文件元数据和目录相关的操作,都是通过适配方式适配到java.io.File的对应API来完成的,适配过程简单,代码清晰 ...
- 51nod1934:受限制的排列 (分治+组合数)
对于一个 11 到 nn 的排列 p1,p2,⋯,pnp1,p2,⋯,pn ,我们可以轻松地对于任意的 1≤i≤n1≤i≤n 计算出 (li,ri)(li,ri) ,使得对于任意的 1≤L ...
- Servlet读取配置文件的三种方式
一.利用ServletContext.getRealPath()[或getResourceAsStream()] 特点:读取应用中的任何文件.只能在web环境下. private void text3 ...
- Java笔记(五)
泛型:JDK1.5版本后出现的新特性.用于解决安全问题,是一个类型安全机制. 好处:将运行期间出现问题ClassCastException,转移到了编译时期.方便程序员解决问题,让运行时问题减少. 避 ...
- [APIO 2015] 雅加达的摩天楼
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4070 [算法] 考虑将每个"Doge"向其所能到达的楼连边 直接 ...
- npm安装cnpm淘宝镜像
npm set registry https://registry.npm.taobao.org # 注册模块镜像 npm set disturl https://npm.taobao.org/d ...
- java中约瑟夫环代码实现
问题原型: 传说在很久很久以前,有一架搭载着n个人的飞机出现了故障,迫降在了一个荒岛上.飞机彻底报废后,这些人用飞机的残骸建成了一艘只能容纳一个人乘坐的小船,那么怎么去确定这n个人中哪个人有资格上船呢 ...
- PHP正则匹配中文汉字注意
preg_match('/^[a-zA-Z\x{4e00}-\x{9fa5}]+$/u', $str) 如上,是匹配字母或者汉字的,一定要在后面加模式修饰符 u , 不然就出错! u (PCRE_UT ...