关于JavaScript变量提升那点事儿

ECMAScript在浏览器端运行被称为JavaScript

在浏览器端JavaScript是一种描述型脚本语言,不需要编译成中间语言,而是由浏览器按代码块顺序进行动态地解析与执行。

关于作用域

ES6之前,只有全局作用域和函数作用域;ES6引入了块级作用域。作用域是代码执行过程中的变量、函数或者对象的可访问区域。

  • 全局作用域:当定义变量的地方没有被 function 包括则是全局变量
  • 函数作用域:在函数内部定义的变量就是处于函数作用域中
  • 块状作用域:类似于 if、switch 条件选择或者 for、while 这样的循环体即是所谓的块级作用域

关于变量的生命周期

变量的生命周期包含着变量声明、变量初始化、以及变量赋值三个步骤;其中声明步骤会在作用域中注册变量,初始化步骤负责为变量分配内存并且创建作用域绑定,此时变量会被初始化为 undefined,最后的分配步骤则会将开发者指定的值分配给该变量。

关于预编译

JavaScript代码不需要编译成一个其它可执行的文件,但是js代码在执行之前会有一个准备过程,这个准备过程叫作预编译。
预编译的过程是不可见的,也不会产生额外的文件。

预编译期间会主要完成两件事情:

  1. 按顺序扫码代码块,如果发现语法错误,停止工作并报错;
  2. 若没有语法错误,做声明变量和初始化变量的操作即所谓的变量提升操作;

先看一道简单的题目

  

这道题目很简单,但是却很能说明问题。

提升操作

  • 使用var声明的变量的提升:把所有带有var关键字的变量名,提升到当前代码块的开始,并设初值为undefined。
  • 函数提升:把所有用声明式定义的函数,提升到当前代码块的开始,注意是做函数整体的提升。

具体细节如下

只提升加var的变量,没有var不提升

关于JavaScript变量提升那点事儿_第1张图片

如图,没有var,变量名没有提升,相当于没有声明变量a就直接使用它,会出现引用类型错误。

if结构中的变量提升

关于JavaScript变量提升那点事儿_第2张图片

如图所示,变量提升一定是发生在预编译期(提升之后才会进入代码的执行期),而变量的提升与if条件语句是否成立无关。只要有var就会提升。

for循环中的变量提升


同样会做变量提升。

函数内部的变量提升

关于JavaScript变量提升那点事儿_第3张图片

函数内部定义的变量,不可能提上到函数的外部。如图会直接报错。
关于JavaScript变量提升那点事儿_第4张图片

函数内部的变量只会体升到函数的开始位置。

只提升声明式定义的函数

定义函数有两种方式:

  • 声明式:function f(){}
  • 函数表达式: var f = function(){}

关于JavaScript变量提升那点事儿_第5张图片

函数提升是整个函数体提升,变量提升是提升的变量名。
关于JavaScript变量提升那点事儿_第6张图片

如上图所示,通过表达式定义的函数提升,报了一个TypeError的错误;是因为预编译期将var关键字提升,也就是说这里的 f就是一个普通变量,它的初值被赋为undefined;当代码执行到第11行 f();时就相当于是 undefined();,所以肯定会报类型错误。

函数与变量同时提升

关于JavaScript变量提升那点事儿_第7张图片

当函数名与变量名同名,且同时提升,以函数为准。
理由是 函数是一等公民,地位高于变量。

提升不能跨script标签

关于JavaScript变量提升那点事儿_第8张图片

开始那道题的答案

关于JavaScript变量提升那点事儿_第9张图片

ES6中的变量提升以及暂时性死区

在 ES6 中以 let 与 const 关键字声明的变量会在作用域头部被初始化,不过这些变量仅允许在实际声明之后使用。在作用域头部与变量实际声明处之间的区域就称为所谓的暂时死区(Temporal Dead Zone),TDZ 能够避免传统的提升引发的潜在问题。

小结

以上,就是关于JavaScript变量提升的知识小结。

你可能感兴趣的:(关于JavaScript变量提升那点事儿)