详解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 一:理解工厂模式 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式. 简单的工厂模式可以理解为解决 ...
随机推荐
- 侧方位停车想一次过,掌握边线30cm很重要!
侧方位停车要想一次过关,关键在于保持车身距离库边线30cm左右的距离.但是,往往有很多学员掌控不好这个距离,导致倒库时压线.那么,如何找准这个30cm呢?下面,小编就来教大家方法,赶紧学习吧! 侧方位 ...
- complex brain network
Organization, development and function of complex brain networks The Brain as a Complex System: Usin ...
- hadoop集群异常问题总结
1. Could not find or load main class java.library.path=.opt.hadoop.lib 我的环境上是 hadoopopts变量的配置问题,至于为啥 ...
- ubuntu 使用命令行清空回收站
sudo rm -rf ~/.local/share/Trash/*
- 【旧文章搬运】ntfs中的文件名排序规则~
原文发表于百度空间,2011-04-05========================================================================== 在分析nt ...
- 在项目中添加全局的 pch 文件
说明,本片博文仅仅是方便自己以后在添加 pch 文件的配置时候参照使用,担心一些配置的路径由于时间而遗忘. (1)建一个 pch 文件 注意下面要 在 Targets 后打上 对号 (2)对该文件进行 ...
- Rusty String
题意: 给定一个含有两种字符'V','K'以及?的字符串,问该串可能的循环节. 解法: 首先如果对于$d$,我们有不存在 $(j-i) | d$ 且 $S_i = 'V', S_j = 'K'$ 的 ...
- 解决 'chromedriver' executable needs to be in PATH.'报错
试了把chromedriver.exe放到chrome安装文件下,python安装文件下,然后把路径配到path里,均无用. 最后是修改函数调用得以解决: from selenium import w ...
- 如何将linux主机接入到网络中
前言: 这篇博客的主旨就想文章题目说的那样,当我们拿到一台新的系统时,我们怎么实现让你的主机连接到网络中.配置网络就是给你的系统配置IP地址,子网掩码,网关以及DNS.也就是说配置好这几项计算机上网的 ...
- Java简单的数组用法尝试,和C语言很不一样
public class Main { static int ARRY_LONGTH=100; static int[] getRandomArr(int n){ int[] randomArr; r ...