你不知道的JavaScript(上)1

317 阅读3分钟

利用空余时间读完这三本小黄书,顺手写写笔记与感想,一定有很大的收获。

第一章 作用域是什么?

还没读几行,一个观点狠狠的冲击着我的认知。

尽管通常将JavaScript归类为“动态”或“解释执行”语言,但事实上它是一门编译语言。

???

我寻思着JS不是解释性语言吗?缓缓打出三问号,继续捋。

编译语言VS解释性语言(个人理解)

  • 编译语言:编译器先将编程语言转换成中间文件(如java的.class的文件),再将它转换成机器语言。
  • 解释性语言:直接将变成语言转换成机器语言,但是依赖解释器。解释一行,执行一行。

我还是没搞明白

于是我参考到了这篇文章: baijiahao.baidu.com/s?id=159152…

但是,我还是偏向解释性语言...

关于文章里面的知识点,咱慢慢捋。

编译语言中,一段源代码在执行前到底经历了什么?

  • 分词/词法分析

var a = 'trio'; 分解成 var、a、=、'trio'、;

  • 语法分析

将上一步的成果词法单元转换成一颗抽象语法树(AST)

  • 代码生成

将AST转换成机器能识别的代码

复杂吗?书中指出JavaScript引擎要比那些编译过程只有三个步骤的语言的编译器,要复杂的多。

对于JavaScript来说,大多数编译发生在代码执行前的那一刻!而参与JavaScript工作的有三个重量嘉宾:

  • 引擎

从头到尾负责整个程序的编译及执行

  • 编译器

语法分析、代码生成

  • 作用域

负责收集并维护由所有声明的标识符组成的一系列查询

模拟一下

var a = 2; 
// 我们都知道 上述代码相当于 
var a; // ①
a = 2; // ②

引擎也是这么认为的

其中①是编译器在编译时干的活,②是引擎自己的工作。

编译器会向作用域确定受否有这个变量,是否需要再次声明。而引擎则会执行赋值操作。

深层次解释变量提升

JS引擎在代码执行的前一刻会对其进行编译(比如 var a = 2; var a 部分直接交给了编译器),而编译器会告诉作用域,去帮我创建一个a变量,但是没有值。所以编译的过程,也就是变量提升的过程。

LHS和LRS

number = 1; // ①
console.log(number); // ②

这两行代码,引擎都需要去问作用域查询number这个变量是否存在以及是否有值。但是我们细品一下,他们之间有所不同。

①要找到number这个变量,根本不在乎你有没有值,我在乎的是你这个玩意儿有没有。(LHS)

②要找number这个变量,我要彻彻底底的取到你这个值,传入我的log函数。(RHS)

考虑以下代码
function foo(a){
    console.log(a)
}
foo(2)

执行foo的时候,对foo进行RHS。隐式的a=2,对a进行LHS。对a进行RHS,传入log函数。那console.log是个啥玩意儿?引擎又需要对console这个对象进行RHS。

之前读过这部分,所以接受的很快。做个题。
function foo(a){
    var b = a;
    return a + b;
}
var c = foo(2)

执行var c = foo(2),对c的LHS查询,对foo的RHS查询。传入参数2,对a的LHS查询,执行 b = a,对b的LHS查询,对a的RHS查询,return a + b ,对a、b分别RHS。

区分LHS和RHS的必要性

a = 1;  //不报错(非严格模式) LHS查询
console.log(a)  // ReferenceError    a is not defined  RHS查询

我们可以看出:

  • 如果RHS查询在所有嵌套的作用域中都没有答案,直接报错。
  • 如果LHS查询在全局作用域中也无法找到目标变量,则全局作用域就会友好的为引擎创建一个。

这也可以从更深的角度出发解释为什么都是对变量的查询,一个报错,一个不报错。

第一章End