- 第一部分 作用域和闭包
- 第1章 作用域是什么
- 1.1编译原理
- 1.2理解作用域
- 1.3作用域嵌套
- 1.5异常
- 第2章 词法作用域
- 第3章 函数作用域和块作用域
- 第5章 作用域和闭包
- 第1章 作用域是什么
- 第二部分 this和对象原型
- 第1章 关于this
- 第2章 this全面解析
- 第3章 对象
- 第4章 混合对象“类”
- 第5章 原型
- 第6章 行为委托
之前被好友推荐过《你不知道的JavaScript》这一系列的书籍。上中下三本书都不算厚,内容也是比较独立。本来是打算一个月内看完这本上卷和下卷,可总是因为自己的懒惰读了一个月才断断续续读完上卷。不得不说单是粗略的读完上卷就让我很有收获,下面是对上卷部分的读书笔记,不是什么文档和教程,仅仅供自己学习记录,欢迎各位路过的大佬能指出理解错误的地方以及意见。
第一部分 作用域和闭包
第1章 作用域是什么
1.1编译原理
首先,我也是学习JavaScript一开始,找到资料里面就说JavaScript是一门“解释型”语言。但是其实JavaScript是一门编译语言。
在传统的编译语言中,一段源代码执行前会先经过一段叫做编译的操作,而编译一共有如下3个过程。
- 分词/词法分析(Tokenizing/Lexing)
这个过程将把编程语言的字符串分解为有意义的代码块,这些代码块被称为词法单元(token)
var a = 2;
//就会被拆解成 var、a、=、2、; 这些都是词法单元
//而空格是否属于此法单元取决于是否有意义,
//这里的var a = 2;中的任何一个空格都没有意义
- 解析/语法分析(Parsing)
把众多词法单元组成的词法单元流(数组)转换成一颗树的结构,叫抽象语法树(AbstractSyntaxTree,AST)
var a = 2;
//这句语句转化为树的结构是一个叫做VariableDeclaration
- 代码生成
将语法树转化为可执行的代码过程。
其他的语言的编译在构建前,而JavaScript在执行前也会进行这编译3部曲
1.2理解作用域
对var a = 2;处理时候,具体的编译器是这样工作的。
//1 遇到 var a 编译器会在当前作用域中的一个集合查询是否有a这个变量,
//如果有就继续进行第2步编译动作,
//如果没有会要求当前作用域在自己的这个集合中声明一个新的a变量
//2 遇到 a = 2 编译器为这条语句生成运行时候的代码,供运行时候使用。
//这时候编译器要在生成的代码中表达出 a=2这个意思,所以在生成代码时候,
//需要一个a变量,先去找当前的作用域中的集合是否含有这个变量,
//如果没有就去上一层找。直到找到为止,否者就是报错。
在这里注意的是在步骤2中,编译器会查找作用域集合中时候会有2种不同的查找方式,一种是LHS,一种是RHS。也就是左查询与右查询。这个和我在学习C++中左值右值时候,我觉得十分相识。也就是通过最原始的“=”进行理解,左边是被填充的,右边是去填充的。
var a = 2;//这里编译器生成代码时候,会去当前作用域集合中找a变量,然后赋值为2。
//你可以理解为是找到这片叫做a空间,然后填充上2这个数据,
//所以这里是左查询,也就是找到被填充的a空间
console.log(a)//这里编译器生成代码时候,会去当前作用域集合中找a变量,然后打印出来。
//你可以理解为是找到这个叫做a的变量里面的值,然后使用这个值,
//所以这里是右查询,也就是找到去填充(或者理解为取出来使用)的a空间里面本身的值!!!
1.3作用域嵌套
其实书中这部分的内容讲的就是作用域链,也就是对var a = 2;处理时候,具体的编译器工作的第二步中需要一个a变量,先去找当前的作用域中的集合是否含有这个变量,如果没有就去上一层找。直到找到为止,直到最顶层没有报错为止。这就是一直往上的查找就是顺着作用域链。
var b = 3
function foo(a){
console.log(a+b)
}
foo(2)//4
//这里的function内部是自己的函数作用域,function外面是全局作用域。
//function内部作用域没有b变量,为什么还能具体工作?
//就是因为function中没有,所以找上一级,然后上一级中就有b,就可以使用
//这种机制就是作用域嵌套,或者作用域链。
//我反正是理解为,子作用域可以使用父作用域,但是父作用域不可以反过来使用子作用域。
//当然这里的什么父、子作用域是个人为了理解,自己说的,不是什么术语。
1.5异常
前面都是顺着作用域链能查找成功的时候,但是我们也说过,如果找不到会报错。这里我们查找有2中情况。自然左右查找不到,报错是不一样的。
这里小小验证一下书上讲的左查询吧。
a = 2//这里没有var 声明。但是a=2是左查找,所以左查询热心的会在全局作用域中的集合里面创建一个空的a变量空间。
console.log(a)//右查找结果是2
"use strict"
a = 2//不好意思,这次左查询无法帮助生成一个空的a变量空间了,
//单单是这一句语句就会因为左查询失败,报ReferenceError
console.log(a)//右查找,肯定失败,这句本生也是右查找失败报ReferenceError,
//不过前一句本来就是错,压根也不会运行到这一句。
第2章 词法作用域
第3章 函数作用域和块作用域
第5章 作用域和闭包
第二部分 this和对象原型
第1章 关于this
第2章 this全面解析
第3章 对象
第4章 混合对象“类”
第5章 原型
第6章 行为委托
未完待续,周六整理完第一部分