《你不知道的JavaScript》读书笔记(一):JS是如何查找变量的
这本书之前囫囵地看了一遍,确实点明了很多以前不清不楚的点,但是仅仅看一遍是没什么用的,最近面试遇到不少原理相关的题感觉答得不理想,回头看下其实以前都理解过,但是没有记下来,正好结合实际的问题来再学习一下书上的内容。
第一个问题:JavaScript是如何查找变量的?
第1部分 作用域和闭包
第1章 作用域是什么?
编译原理
这本讲解JavaScript的书首先讲的却是编译原理,一开始看起来让人费解,但实际上从后面内容我们可以发现,JavaScript的很多特性都与编译原理有着极大的关系。我们通常称JavaScript是动态解释执行语言,因为它不是提前编译的,而是根据执行时的情况来对代码进行处理。
在传统编译语言的流程中,代码的执行通常分成三个步骤:
- 分词/词法分析(Tokenizing/Lexing)
将语句分解成词法单元(Token),例如 var a = 2; 会被分解成: var、a、=、2、;。需要注意的是分词和词法分析有少许的区别,
如果词法单元生成器在判断a是一个独立的词法单元还是其他词法单元的一部分时,调用的是有状态的解析规则,那么这个过程就被称为词法分析。
理解不了这一句中的 有状态的解析规则
- 解析、语法分析(Parsing)
将词法单元流转换成树形结构的的过程。这个树被称为“抽象语法树”(Abstract Syntax Tree,AST).
- 代码生成
将AST转换成可执行代码的过程。简单来说就是把 var a = 2; 的AST转化为一组机器指令,用来创建一个叫做a的变量(包括分配内存),并将一个值储存在a中。
与传统编译语言的编译器相比,JavaScript引擎要更复杂,最明显的区别就体现在编译时间上,JavaScript引擎没有时间进行优化,编译过程不是在构建之前,通常发生在代码执行前的几微秒内。在作用域的背后,JavaScript引擎使用了各种方法(比如JIT延迟编译甚至实施重编译)来保证性能。
理解作用域
在理解作用域之前还有一些前置的概念需要理解,在JavaScript执行的时候有三个重要组件:
- 引擎:负责整个JavaScript程序的编译及执行过程
- 编译器:负责语法分析和代码生成
- 作用域:负责收集维护由所有声明的标识符(也就是变量)组成的查询,并根据严格的规则确定执行的代码对变量的访问权限
还是上面的var a = 2;这个例子,编译器在处理时会分成两步:
var a,编译器先询问作用域同一个作用域中是否已经有这样一个名称的变量。如果是,编译器则忽略这个声明,继续编译;如果否,编译器则要求作用域在当前作用域的集合中声明一个新的变量,命名为a。a = 2,编译器会为引擎生成运行所需要的的代码来执行这个赋值操作。引擎运行时同样先询问作用域,当前作用域集合中是否有一个叫做a的变量。如果是,引擎就会使用这个变量;如果否,引擎会继续查找该变量了(如何查我们在下一节说明,因为查找的是其他作用域的)。
如果再细致地说明引擎的查找过程可以把它分成LHS查询和RHS查询,“L”和“R”很好理解,就是左侧和右侧,具体来说就是一个赋值操作的左侧和右侧。
变量在赋值操作左侧时就进行LHS查询,出现在右侧时就进行RHS查询,但实际上会这么简单吗?肯定不是,LHS其实是找到变量的容器本身并对其赋值,RHS则相反,意思比较接近于“取到它的原值”或“得到某某的值”。看下面这个例子:
console.log(a);
这里对a的引用就是一个RHS引用,因为没有为a赋任何值,而是获取了a的值并传递给了console.log()。而相比a = 2,很明显就是把“= 2”交给了“a”。
也就是说LHS和RHS并不是简单的左侧和右侧,而是“赋值操作的目标是谁”和“谁是操作的源头”。
理解了之后再看这个例子,除了一个RHS操作是否还能找出一个LHS操作呢?
function foo(a){
console.log(a); // 2
}
foo(2);
这是一个很容易被忽略的细节,代码中存在一个隐式的a = 2操作,2倍当做参数传递给了foo()函数,这里要给参数a分配值,所以需要一次LHS查询。
作用域嵌套
这个问题说起来很简单,就是当引擎需要变量时,会先在当前作用域寻找,如果没有这个变量就到上一级作用域查找,直到最外层,也就是全局作用域,到达这里以后即使没找到也会停下来。
function foo(a){
console.log(a + b); // 2
}
var b = 2;
foo(2); // 4
异常
上面我们费了半天劲来理解LHS和RHS有什么意义呢?看下面这段代码:
function foo(a){
console.log(a + b);
b = a;
}
foo(2);
显而易见这段代码会报异常,因为对b的RHS查询无法找到该变量,b是未声明的变量,但如果是进行LHS查询则不同,上面说了,引擎在当前作用域未能查找到对象就会向上一级,直到全局作用域还未能找到时,全局作用域就会创建一个具有该名称的变量,并将其交给引擎(前提是在非“严格模式”下)。偶尔会看到一些可以印证这一例子的不规范代码——未声明的变量被使用,如果是在ES5的“严格模式”下,会和RHS一样报ReferenceError的异常。

《你不知道的JavaScript》读书笔记(一):JS是如何查找变量的的更多相关文章
- 你不知道的javascript读书笔记3
概述 这是我看<你不知道的JavaScript(中卷)>中关于类型检查的笔记,供以后开发时参考,相信对其他人也有用. typeof 我们知道js中有七种内置类型:undefined, nu ...
- <你不知道的JavaScript>读书笔记
近几天看了一本不错的 JavaScript 的书,是 Kyle Simpson 写的 <You Don't know JS>.这本书是 Kyle Simpson 在 Github 上的开源 ...
- 你不知道的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 读书笔记
由于自己在对数组操作这块比较薄弱,然后经高人指点,需要好好的攻读一下这本书籍,原本想这个书名就比较高深,这下不好玩了.不过看着看着突然觉得讲的东西都比较基础.不过很多东西,平时还是没有注意到,故写出读 ...
- 《你不知道的JavaScript》笔记(一)
用了一个星期把<你不知道的JavaScript>看完了,但是留下了很多疑惑,于是又带着这些疑惑回头看JavaScript的内容,略有所获. 第二遍阅读这本书,希望自己能够有更为深刻的理解. ...
- 【你不知道的javaScript 上卷 笔记1】 javaScript 是如何工作的?
一.什么是作用域? 作用域是用来存储变量以及方便寻找变量的一套规则. 二.javaScript 编译过程(编译发生在代码执行前的几微妙) 分词/词法分析(Tokenizing/Lexing)-> ...
- 【你不知道的javaScript 上卷 笔记5】javaScript中的this词法
function foo() { console.log( a ); } function bar() { var a = 3; foo(); } var a = 2; bar(); 上面这段代码为什 ...
- JavaScript读书笔记(1)
从今天开启每天看书记笔记模式,<JavaScript高级程序设计(第3版)> 1. Javascript最初是为了解决输入验证器的问题,现在已经发展成一门复杂的语言: 2. 语言标准为E ...
- 高性能的JavaScript -- 读书笔记
高性能的JavaScript 一. 加载和运行 将脚本放在底部 脚本下载解析执行时,页面已经加载完成并显示在用户面前 成组脚本 减少外部脚本文件数量,整合成一个文件 延迟脚本 动态脚本元素 ...
随机推荐
- (续 2 )在深度计算框架MindSpore中如何对不持续的计算进行处理——对数据集进行一定epoch数量的训练后,进行其他工作处理,再返回来接着进行一定epoch数量的训练——单步计算
内容接前文: https://www.cnblogs.com/devilmaycry812839668/p/14988686.html https://www.cnblogs.com/devilmay ...
- 【安装】SQL SERVER 彻底卸载清除
-----2024年8月6日09:40:13 -----bayaim, 以下内容纯属百度网络搜到,如有侵权请联系及时删除 SQL SERVER 如果卸载不干净,就会导致下一次安装失败,下面是卸载的步 ...
- springboot认证方案一
这里给出集成oauth2后的简单认证方案架构图
- brpc linux 下编译构建
brpc 在 linux 下编译构建,比在 mac 下还要更复杂些,mac 下可以走官方说明编译成功,过程中也需要进行一些配置调整. 在 linux 通过 bazel 最终实现了 brpc 编译通过. ...
- 猜数游戏[USACO2008] Haybale Guessing G
$ Haybale \ Guessing \ G $ (猜数游戏) 解题报告 \(Diffculty:\) \(\color{purple}省选/NOI-\) 传送门1:(HZOIER) 传送门2:( ...
- 全网最适合入门的面向对象编程教程:38 Python常用复合数据类型-使用列表实现堆栈、队列和双端队列
全网最适合入门的面向对象编程教程:38 Python 常用复合数据类型-使用列表实现堆栈.队列和双端队列 摘要: 在 Python 中,列表(list)是一种非常灵活的数据结构,可以用来实现堆栈(st ...
- Mac 上几款 Telegram App 的区别
Mac App Store 上有 Telegram 和 Telegram Lite 两款应用,而 Homebrew 上有 telegram 和 telegram-desktop 两款应用.下面介绍一下 ...
- C++:使自定义类支持迭代器
概述 在 C++ 中,链表迭代器是一种用来遍历链表(如 std::list)元素的工具.链表是一种数据结构,其中每个元素(节点)包含一个数据值和一个指向下一个节点的指针.链表迭代器允许以类似于数组的方 ...
- logistic和softmax
一直觉得logistic regression就是softmax的一种特殊的形式,softmax是多类,logistic是两类. 但是今天仔细想了想logistic的意义以及softmax的意义,感觉 ...
- 通用能力及AI核心能力表现优异!合合信息智能文档处理系统(IDP)高评级通过中国信通院评估
数字经济快速发展的背后,全球数据总量呈现出爆发式增长趋势.智能文档处理(IDP)技术能够高效地从多格式文档中捕捉.提取和处理数据,帮助机构和企业大幅提升文档处理效率,节约时间和人力成本.近期,合合信息 ...