作为初学者,浅聊一下我对JavaScript的作用域的理解

0 阅读3分钟

JS引擎

JS是一门轻量级解释型编程语言,依赖于JS引擎驱动执行语言。而JS引擎又分两类:

1.浏览器,比如Google,主要靠其内置的引擎,我们称为v8引擎

2.node 用通俗形象的话说,v8引擎就是JavaScript语言执行的发动机,是让node.js和Chrome正常运行的保证。

JS的执行过程

JS的执行过程分为五个阶段,由v8引擎为其提供运行环境,使JS代码能够高效运行

  1. v8 会读取代码,并不会第一时间执行,而是先编译(梳理)
  2. 分词:将代码分成一个一个的词法单元
  3. 解析:将分词后的单元组织成一个语法树 AST(抽象语法树,抽象语法树是一种树状结构,用于表示代码的语法结构)
  4. 执行:根据语法树生成并执行代码
  5. 返回结果:将执行结果返回给调用者 例如,接下来给一段js代码
var a = 10;//var let const  都是声明变量
 console.log(a)//输出

而如果我把上面语句颠倒,你会发现js语法与传统语法有很大区别,js存在有违人类常识的bug,其存在变量声明提升,运行后不会像c一样报错,而是显示undefine.

image.pngJS 代码执行前,浏览器会先扫描一遍代码,把变量、函数声明提升到当前作用域最顶部,再逐行执行代码

接下来,咱们细聊作用域,即代码能访问变量的范围

1.首当其冲的肯定是全局作用域

即代码最外层声明的变量,全部代码都允许访问。

var a //全局作用域
function foo(){
    console.log(a);//a是函数作用域
}
foo();

2.其次是作为“一等公民”的函数作用域,

需要特别注意的点:在v8的执行过程中,查找一个变量时,只能由函数作用域->全局作用域,不能由全局作用域->函数作用域,同时函数执行时创建的局部变量,在函数执行完毕后就会被销毁。如以下代码输出a=2即说明变量访问先后次序

image.png

3.块级作用域

是ES6(ECMAScript 2015)引入的一种作用域类型,指变量的作用范围仅限于其所在的代码块(即let和const关键字和 {} 包裹的区域)内。变量只在花括号内可以访问。

if(true){
    let a = 10;
     var b=20;
 }//let让变量在花括号内形成块级作用域,在花括号外不能访问
 console.log(a);//不成立

除此之外,还需注意两点:

1.let和const不会带来声明提升

// 例1: var 存在声明提升(可以访问到 undefined)
console.log(x);  // undefined(不会报错)
var x = 10;

// 例2: let 不存在声明提升(声明前访问会报错)
console.log(y);  // ReferenceError: Cannot access 'y' before initialization
let y = 20;

2.const声明的变量是不能重新赋值,而let可以 3.let和const声明的变量都存在暂时性死区,即let和const声明的变量在块级作用域内不能提前访问

{
    // 进入块级作用域,y 就进入了暂时性死区
    console.log(y);  // ReferenceError
    let y = 20;      // 声明后,死区结束
    console.log(y);  // 20
}

三个变量对比:

varletconst
无暂时性死区存在暂时性死区存在暂时性死区
声明前访问不报错声明前访问报错声明前访问报错
允许重复声明不允许不允许
允许重复赋值允许重复赋值不允许重复赋值