初学javascript的时候,一直关注的在dom操作,不断成长的过程中,开始渐渐接触基础核心。
所以来持续更新这篇文章,从而记录自己的学习历程。
1. 编译原理
1.1 词法分析
程序 var a = 2; 被分解成 词法单元 var , a , = , 2 , ; ,
1.2. 语法分析
词法单元 => AST(抽象语法树)
1.3. 代码生成
AST => 可执行代码
2. 编译介绍
2.1 引擎:负责整个js 编译和执行过程
2.2 编译器:语法分析/代码生成
2.3 作用域:查询变量+设置他们的访问权限
eg:
var a = 2
- 对于var a 编译器会询问作用域 是否有 a 存在同一个作用域中,若有,忽略该声明,继续编译;否则在当前域声明新变量,命名为a
- 对与 a=2 引擎 询问 作用域 是否存在一个a,存在则引用,不存在,就继续查找,找到了就把2赋值给a,没有则抛出一个异常。
(编译器查找a是否存在过的时候,实际是引擎进行LHS/RHS 查询)
a=2 对于a的查询 ------LHS(谁是赋值目标用)
console,log(a) 对于a的查询 ------RHS (赋值目标的源头的时候用)
RHS 查询的时候 从嵌套的作用域到全局作用于无法找到变量的时候 会抛出 ReferenceError异常
LHS 查询到 全局作用域 也没找到 会在全局创建一个该名称的变量 (非严格模式下)
ReferenceError:与作用域判别失败相关
TypeError:作用域判别成功,对结果的操作是不合理/非法的
3. 作用域
eg:
for(var i=0;i<10;i++){
console.log(i)
}
console.log(`outside=${i}`)
我们可以看出 我们想用块作用域来限制i;然而在for外 还是得到了i
这是var 绑定造成的
ES6中 我们可以用let/const 来避免这种情况
let用来声明变量,const来设置常量
4. 提升
var a = 2
编译器 实际是分成了2部分 var a 和 a=2
var a 是我们的定义声明 【编译阶段】
a = 2 是我们的赋值声明 ,它在此会等待【执行阶段】
所以我们这样就可以清楚的解释变量提升的问题
console.log(a);
var a=2;
// undefined
也就是 这里的var a 会先进入编译阶段;然后在执行阶段的时候 先console.log 后才会 a=2;
所以最后的结果是undefined
函数提升的问题类似
foo();
var foo=function test(){
console.log(1);
}
// chrome: foo is not a function
报错可知:编译时 var foo ;执行的时候 foo() 报错foo 不是一个函数;因为这时候的foo还没有赋值成为一个函数
同时注意 这里的错误是typeError 而不是 ReferenceError
因为这里是对foo操作不合法造成的
5. 词法作用域与动态作用域
var a = 2;
function foo() {
console.log( a );
}
function bar() {
var a = 3;
foo();
}
bar();
- 如果处于词法作用域。变量a首先在foo()函数中查找,没有找到。于是顺着作用域链到全局作用域中查找,找到并赋值为2。所以控制台输出2
- 如果处于动态作用域,同样地,变量a首先在foo()中查找,没有找到。这里会顺着调用栈在调用foo()函数的地方,也就是bar()函数中查找,找到并赋值为3。所以控制台输出3
而 js 使用的是词法作用域
持续更新ing!
网友评论