一文搞懂 JavaScript 作用域

26 阅读2分钟

引言

1.JS 引擎

JS能在浏览器的v8引擎和Node引擎(v8)上运行

JS的执行

1.v8 会先读取代码,并不会第一时间执行,而是要先编译(梳理)
2.然后进行分词:将代码拆成一个一个的词法单元
3.接着进行解析/语法分析:将词法单元组织成一个语法树 AST (抽象语法树 Abstract Syntax Tree)
4.最后执行:根据 AST 生成代码执行

什么是作用域?

作用域(Scope) 是 JS 中用来管理变量访问范围的规则,它决定了哪些变量可以在哪里被访问。

JS中的三种作用域

1.全局作用域
在整个程序中都能访问的变量

var a = 10; // 全局变量

function foo(){
    console.log(a); // 可以访问变量a
 }
 foo();
 console.log(a); // 可以访问变量a

这一整个程序所在就是一个全局作用域

2.函数作用域
在函数内部声明的变量,只能在函数内部访问

function foo(b){ //形参b在函数内部
    var a = 10; //函数内部变量
    console.log(a); //可以访问变量a
}
foo(b);
console.log(a); // 不能访问变量a

function foo(){}会生成一个函数作用域,函数内部声明的变量,函数外部无法访问

3.块级作用域(ES6+)
使用 let 或 const 在 {} 块内声明的变量

{
    let a = 10; // 块级变量
    const PI = 3.14;
    console.log(a); // 可以访问变量a
}
console.log(a); // 不能访问变量a

let 或 const + {} 会形成块级作用域
let不会带来声明提升(var声明的变量如果在调用后面,v8会在将代码拆分时将变量声明提到作用域顶部,这叫声明提升)
const 声明的是常量,不能重新赋值

作用域链

在v8的执行过程中,查找一个变量时,会先在当前作用域中查找,如果找不到,就回去外层作用域中查找,直到找到全局作用域,还是找不到,就会报错

var c = 100;

function foo(){
    var b = 10;
    if(true){
    let a  1;
    console.log(a); // 先找内层作用域
    console.log(b); // 内层找不到,向外层找
    console.log(c); // 继续向外,找到全局作用域
   }
}
foo()

总结

1.三种作用域类型

类型声明方式作用范围特性
全局作用域函数外声明整个程序挂载到 window,易污染
函数作用域函数内声明函数内部私有性好
块级作用域let/const+{}块内有效ES6+ 新增

2.关键特性
声明提升:var 会提升到作用域顶部

console.log(a);
var a = 10;

在执行时

var a;
console.log(a);
a = 10;

let/const有暂时性死区

var a = 100;
if(true){ // 暂时性死区
    console.log(a);
    let a = 10;
}