你不知道的javaScript上卷(第一章 作用域是什么)
在写这篇博客时这本书我已经是看过一遍了,为了加深印象和深入学习于是打算做这系列的前端经典书籍导读博文,大家如果觉得这本书讲的好可以自己买来看看,我是比较喜欢看纸质版书的,因为这样才有读书的那种感觉。
本期我给大家讲述的是 前端经典js书籍 <<你不知道的javaScript(上卷)>> 第一章内容的知识点总结和讲解。
1.1 编译原理
尽管通常将js归类为“动态”或“解释执行”语言,但事实上它是一门编译语言。但与传统的编译语言不同,他不是提前编译的,编译结果也不能在分布式系统中进行移植。在传统编译语言的流程中,程序中的一段源代码在执行之前会经历三个步骤,统称为“编译”。
1>分词/词法分析
这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代码块被称为词法单元。例如,考虑程序 var a=2;这段程序通常会被分解成为下面这些词法单元 : var 、a、=、2、;。空格是否会被当做词法单元,取决于空格是否在这门语言中具有意义。
2>解析/语法分析
这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法结构的树。这个树称为“抽象语法树”(AST)。
3>代码生成
将AST转换为可执行代码的过程被称为代码生成。这个过程与语言、目标平台等息息相关。抛开具体细节,简单的来说就是有某种方法可以将 var a=2 ;的AST转化为一组机器指令,用来创建一个叫做a的变量(包括分配内存等),并将一个值存储在a中。
1.2理解作用域
为了进一步理解,我们需要多介绍一点编译器的术语。在我们的例子中,引擎会为变量a进行LHS查询。另外一个查找的类型叫做RHS查询。我打赌你一定能猜到“L”和“R”的涵义,它们分别代表左侧和右侧。什么东西的左侧和右侧?是一个赋值操作的左侧和右侧。
换句话说,当变量出现在赋值操作的左侧时进行LHS查询,出现在右侧时进行RHS查询。讲得更准确一点,RHS查询与简单地查找某个变量的值别无二致,而LHS查询则是试图找到变量的容器本身,从而可以对其赋值。从这个角度来说,RHS并不是真正意义上的“赋值操作的右侧”,更准确的说是“非左侧”。
考虑以下代码:
1 console.log(a); 其中对a 的引用是一个RHS引用,因为这里a并没有赋予任何值。相应地,需要查找并取得a的值,这样才能将值传递给console.log(...)。
相比之下,例如:
1 a=2; 这里对a的引用则是一个LHS引用,因为实际上我们并不关心当前的值是什么,只是想要为=2这个值赋值操作找到一个目标。
1.3作用域嵌套
当一个块或函数嵌套在另一个块或函数中,就发生了作用域的嵌套。因此,在当前作用域中无法找到某个变量时,引擎就会在外层嵌套的作用域中继续查找,直到找到该变量,或抵达最外层的作用域(也就是全局作用域为止)。
考虑以下代码:
- 1 function foo(a){
- 2 console.log( a+b );
- 3 }
- 4 var b=2;
- 5 foo( 2 ); //4
对b进行的RHS引用无法在函数foo内部完成,但可以在上一级作用域(在这个例子中就是全局作用域)中完成。
把作用域链比喻成一个建筑:第一层楼代表当前的执行作用域,也就是你所处的位置。建筑的顶层代表全局作用域。LHS和RHS引用都会在当前楼层进行查找,如果没有找到,就会乘坐电梯前往上一层楼,如果还没找到就继续向上,以此类推。一旦抵达顶层(全局作用域),可能找到了你所需的变量,也可能没找到,但无论如何查找过程都将停止。
1.4异常
为什么区分LHS和RHS是一件重要的事情? 因为在变量还没有声明(在任何作用域中都无法找到该变量)的情况下,这两种查询的行为是不一样的。
考虑如下代码:
- 1 function foo(a){
- 2 console.log( a+b );
- 3 b=a;
- 4 }
- 5 foo( 2 );
第一次对b进行RHS查询时是无法找到该变量的。也就是说,这是一个“未声明”的变量,因为在任何相关的作用域中都无法找到它。
如果RHS查询在所有嵌套的作用域中遍寻不到所需的变量,引擎就会抛出 ReferenceError异常。相较之下,当引擎执行LHS查询时,如果在顶层(全局作用域)中也无法找到目标变量,全局作用域中就会创建一个具有该名称的变量,并将其返还给引擎,前提是程序运行在非严格模式下。
严格模式下在行为上有很多不同。其中一个行为就是禁止自动或隐式地创建全局变量。因此,在严格模式下LHS查询失败时,并不会创建并返回一个全局变量,引擎会抛出同RHS查询失败时类似的 ReferenceError异常。
小结:作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。如果查找的目的是对变量进行赋值,那么就会使用 LHS查询;如果目的是获取变量的值,就会使用 RHS查询。赋值操作符会导致 LHS查询。=操作符或调用函数时传入参数的操作都会导致关联作用域的赋值操作。js引擎首先会在代码执行前对其进行编译,在这个过程中,像 var a=2 ;这样的声明会被分解成两个独立的步骤:
1.首先,var a 在其作用域中声明新变量。这会在最开始的阶段,也就是代码执行前进行。
2.接下来,a=2 会查询(LHS查询) 变量a并对其进行赋值。
LHS和RHS查询都会在当前执行作用域开始,如果有需要(也就是说它们没有找到所需的标识符),就会向上级作用域继续查找目标标识符,这样每次上升一级作用域(一层楼),最后抵达全局作用域(顶层),无论找到还是没找到都将停止。
不成功的RHS引用会导致抛出 ReferenceError异常,不成功的LHS引用会导致自动隐式地创建一个全局变量(非严格模式下),该变量使用LHS引用的目标作为标识符,或者抛出 ReferenceError 异常(严格模式下)。
以上就是本次的内容,如果觉得这篇博文对你有用或者让你了解了一些新知识那就点波推荐吧。本人爱结交朋友,欢迎大家加我的QQ:825348114,一起进步。
你不知道的javaScript上卷(第一章 作用域是什么)的更多相关文章
- 读《你不知道的JavaScript(上卷)》后感-作用域闭包(二)
github原文 一. 序言 最近我在读一本书:<你不知道的JavaScript>,这书分为上中卷,内容非常丰富,认真细读,能学到非常多JavaScript的知识点,希望广大的前端同胞们, ...
- 读《你不知道的JavaScript(上卷)》后感-浅谈JavaScript作用域(一)
原文 一. 序言 最近我在读一本书:<你不知道的JavaScript>,这书分为上中卷,内容非常丰富,认真细读,能学到非常多JavaScript的知识点,希望广大的前端同胞们,也入手看看这 ...
- 《你不知道的 JavaScript 上卷》 学习笔记
第一部分: 作用域和闭包 一.作用域 1. 作用域:存储变量并且查找变量的规则 2. 源代码在执行之前(编译)会经历三个步骤: 分词/此法分析:将代码字符串分解成有意义的代码块(词法单元) 解析/语法 ...
- 你不知道的JavaScript上卷笔记
你不知道的JavaScript上卷笔记 前言 You don't know JavaScript是github上一个系列文章 初看到这一标题的时候,感觉怎么老外也搞标题党,用这种冲突性比较强的题目 ...
- 【你不知道的javaScript 上卷 笔记3】javaScript中的声明提升表现
console.log( a ); var a = 2; 执行输出undefined a = 2; var a; console.log( a ); 执行输出2 说明:javaScript 运行时在编 ...
- 你不知道的JavaScript(上)作用域与闭包
第一部分 作用域与闭包 第一章 作用域是什么 1.作用域 变量赋值操作会执行两个动作:首先编译器会在当前作用域中声明一个变量(如果之前没有声明过), 然后会在运行时引擎会在作用域中查找该变量,找到就会 ...
- 你不知道的JavaScript 上卷 2/11
第一部分——作用域和闭包 第一章 作用域是什么 1.几乎所有编程语言最基本的功能之一,就是能够储存变量当中的值,并且能在之后对这个值进行访问或修改.事实上,正是这种储存和访问变量的值的能力将状态带给了 ...
- JavaScript词法作用域—你不知道的JavaScript上卷读书笔记(一)
前段时间在每天往返的地铁上抽空将 <你不知道的JavaScript(上卷)>读了一遍,这本书很多部分写的很是精妙,对于接触前端时间不太久的人来说,就好像是叩开了JavaScript的另一扇 ...
- 《你不知道的JavaScript》第一部分:作用域和闭包
第1章 作用域是什么 抛出问题:程序中的变量存储在哪里?程序需要时,如何找到它们? 设计 作用域 的目的:为了更好地存储和访问变量. 作用域:根据名称查找变量的一套规则,用于确定在何处以及如何查找变量 ...
随机推荐
- Winsock网络编程笔记(3)----基于UDP的server和client
在上一篇随笔中,对Winsock中基于tcp面向连接的Server和Client通信进行了说明,但是,Winsock中,Server和Client间还可以通过无连接通信,也就是采用UDP协议.. 因此 ...
- 腾讯Java程序员第二轮面试11个问题,你会几个?
此前,分享了阿里巴巴.网易.百度等多家名企的JAVA面试题. 这也引来了不少程序员网友们的围观. 其中,也有相当一部分网友是已经从事Java开发好多年的程序员,当他们阅读完JAVA面试题的反应是:一个 ...
- Java Enum用法详解
Java Enum用法详解 用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举 ...
- 有关数据传输GET和POST的方法的区别
有关前后端数据交互,主要是通过走http协议通过post或get的方法,拿angularJS来说:通过JS来发送http请求调用相关接口: $scope.apostDate=function(){ $ ...
- 在ASP.NET Core Web API中为RESTful服务增加对HAL的支持
HAL(Hypertext Application Language,超文本应用语言)是一种RESTful API的数据格式风格,为RESTful API的设计提供了接口规范,同时也降低了客户端与服务 ...
- c# word文档与二进制数据的相互转换
最近项目出使用到了将word文档以二进制的方法存到数据库中,并再次读取出二进制数据转换为word文档.最后总结了一下,不多说看示例方法: 代码 , content.Length); ...
- [转载] Java学习之Hessian通信基础
转载自http://blog.sina.com.cn/s/blog_7f73e06d0100xn9j.html 一.首先先说Hessian是什么? Hessian:hessian是一个轻量级的r ...
- 设计模式的征途—23.解释器(Interpreter)模式
虽然目前计算机编程语言有好几百种,但有时人们还是希望用一些简单的语言来实现特定的操作,只需要向计算机输入一个句子或文件,就能按照预定的文法规则来对句子或文件进行解释.例如,我们想要只输入一个加法/减法 ...
- netty 入门(一)
netty Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序.更确切的讲是一个组件,没有那么复杂. 例子 一 Discard服务器端 我们 ...
- Android OOM异常解决方案
一,什么是OOM异常: OOM(out of Memory)即内存溢出异常,也就是说内存占有量超过了VM所分配的最大,导致应用程序异常终止: 二,为什么会产生OOM异常呢? OOM异常是Android ...