详解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滤镜代码级分析
http://blog.chinaunix.net/uid-26000296-id-3322071.html 前一篇文章<为FFmpeg添加自定义滤镜>详细讲述了FFmpeg的滤镜添加步骤 ...
- H264视频通过RTMP直播
http://blog.csdn.net/firehood_/article/details/8783589 前面的文章中提到了通过RTSP(Real Time Streaming Protocol) ...
- poj图论解题报告索引
最短路径: poj1125 - Stockbroker Grapevine(多源最短路径,floyd) poj1502 - MPI Maelstrom(单源最短路径,dijkstra,bellman- ...
- hdu 1753 大明A+B(大数)
题意:小数大数加法 思路:大数模板 #include<iostream> #include<stdio.h> #include<string.h> using na ...
- DDD领域驱动之干货(四)补充篇!
距离上一篇DDD系列完结已经过了很长一段时间,项目也搁置了一段时间,想想还是继续完善下去. DDD领域驱动之干货(三)完结篇! 上一篇说到了如何实现uow配合Repository在autofac和au ...
- 第九章-IO编程
IO是输出输入的意思 在计算机中常用到的数据交换的地方是磁盘, 网络等 输入流是从外面(磁盘, 网络)流进内存 输出流是从内存流到外面(磁盘, 网络) 同步IO是指等待IO完成再继续执行 异步IO是在 ...
- CodeForces - 840D:(主席树求出现区间出现次数大于某值的最小数)
Once, Leha found in the left pocket an array consisting of n integers, and in the right pocket q que ...
- HDU5919 Sequence2
传送门 这道题是主席树好题啊-- 题目大意:给定一个序列,每次给定一段区间,区间内所有不同的数第一次出现的位置排成一个序列,求这个序列的中位数. 其实求中位数并不是很难,只要我们能把这个序列中不同的数 ...
- node process-进程
process对象是一个全局变量,提供Node.js进程的有关信息以及控制进程.因为是全局变量所以可以直接使用
- 各浏览器userAgent汇总
浏览器 navigator.userAgent 备注 IE6 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) IE7 Mo ...