你该知道的JS知识---作用域
作用域是什么?
作用域是当前的执行上下文,在其中的值和表达式“可见”(可被访问)。如果一个变量或表达式不在当前的作用域中,那么它是不可用的。作用域也可以堆叠成层次结构,子作用域可以访问父作用域,反过来则不行。
JavaScript的作用域分为以下三种:
- 全局作用域:在整个JS代码中的任何地方都能使用的变量所创建作用域
- 函数作用域:由函数所创建的作用域,在函数内的变量只能在该函数内部访问,外部无法使用函数内部的变量
- 块级作用域:ES6之前没有块级作用域,之后通过使用let或const关键字,可以在特定的块中创建的作用域,即在一对花括号之内。
代码执行的流程
每段代码在执行出结果之前,都会进行以下步骤,词法分析,语法分析,生成代码
var a = 2;
- 词法分析
词法分析也称为 分词 ,此阶段编译器从左向右扫描源文件,将其字符流分割成一个个的 词 。所谓 token ,就是源文件中不可再进一步分割的一串字符,类似于英语中单词,或汉语中的词。上述例子被分割成 var , a , = , 2 - 语法分析
语法分析会将上一步的词法单元集合分析并最终转换为一个由元素逐级嵌套所组成的代表了程序语法结构的树,即抽象语法树(AST) - 生成代码
最后将上一步生成AST转化为可执行的代码
var let const 的区别
- var 声明的变量存在变量提升,就是把变量提升到当前作用域的顶部,而let和const没有变量提升
console.log(a);
var a=2;
//变量提升
var a;
console.log(a);
a=2;
- var 可以重复声明变量,后面声明的会覆盖前面的。而let和const不可以重复声明变量
- const声明的变量不能再次赋值,而let可以
- var 由于变量提升,它不会存在块级作用域内,let和const由块级作用域
- let 变量有暂死区,在代码块内,使用let命令声明变量之前,该变量都是不可用的。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
作用域的查找规则
当查找变量的时候,会先从当前执行上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的 变量对象 构成的链表就叫做作用域链。