JS系列之三、变量提升&函数提升

323 阅读3分钟

一、前置知识

  1. JS是如何运行的
  • 编译型语言(如:Java),编译步骤分为:词法分析->语法分析->语义检查->代码优化和字节码生成。
  • 解释型语言(如:js),编译步骤为:词法分析->语法分析->生成语法树。
  1. 词法分析阶段
  • 词法分析拆解为三部分:分析形参分析变量分析函数三个部分。 以var answer = 1;举例,在词法分析过程被拆分成了多个token(词法单元)。
    <示例1> image.png
  1. 语法分析
  • 将步骤1.2生成的token转换为抽象语法树(AST),如下示例。
    <示例2> image.png
  1. 执行阶段 js在解释执行阶段,Js引擎是严格按着作用域机制(scope)来执行的,并且Js的变量和函数作用域是在定义时决定的,而不是执行时决定的。具体作用域相关可以参考我的另一篇系列文章《JS系列之二、作用域

截图使用AST解析网站参考地址:esprima.org/demo/parse.…

二、变量提升

  1. 只有声明被提升,初始化不会被提升 <示例3>
  • 源语句
var a='我是一个变量'
  • 提升后的语句
var a; // 声明被提升
a= '我是一个变量';
  1. 声明会被提升到当前作用域的顶端
  • 参考目录一下第三小节《执行阶段》的介绍,Js引擎是严格按着作用域机制(scope)来执行的 <示例4> 以函数作用域示例
  • 源代码语句
function A(){
//...其他逻辑
var a = '我是函数内部变量'
}
  • 提升后语句
function A(){
var a;// 提升到作用域顶端
//...其他逻辑
a = '我是函数内部变量'
}

三、函数提升

函数的声明有两种方式:声明式和表达式

声明式:function A(){...}
表达式:var a = function(){...}

  1. 函数声明和初始化都会被提升
  2. 函数表达式只提升声明 上面1、2可共同参考下面<示例5>
// 未提升前的源代码
console.log(a);
console.log(b);
function a() {}
var b= function(){}

// 提升后的代码
function a() {} // 函数声明和初始化都会被提升
var b; // 函数表达式只提升声明

console.log(a); // function a() {}
console.log(b); // undefined
var b= function(){}

四、提升优先级

  1. 函数的优先级高于变量,且函数与变量存在同名的情况,函数会覆盖变量
// 提升前的源代码
console.log(a);
console.log(a());
var a = 3;
function a() {
    console.log(10);
    return "im's function"
}
console.log(a)

// 提升后的代码
function a() {
    console.log(10);
    return "im's function"
}
// var a; //被覆盖掉了 
console.log(a); // a() {console.log(10);return "im's function"}
console.log(a()); // im's function
a = 3; // 相当于给函数a赋值
console.log(a) // 3
  1. 这里的覆盖关系还可以参考活动对象

JS运行的时候,会产生一个活动对象Active Object,简称AO 这个AO是干什么的呢,通俗点讲就是这个AO 在分析形参分析变量分析函数中记录和整合变量及函数。类似于下面代码

var a = 1;
function a() {}

// AO挂载属性:

真实的AO过程并不是这样,这里只是方便理解通俗举例。

var AO ={}
// 1.分析变量:发现了一个a变量
AO.a=undefined
//2. 分析函数:发现了一个a方法
AO.a=function() {} // 这里覆盖掉了同名变量a

五、结语

本篇文档到此结束,有任何不妥和问题之处欢迎各位大佬能及时指正。