全面理解JS(函数)执行顺序

2021年9月1日 3点热度 0条评论 来源: guolinengineer

第一步: 检查语法错误

  浏览器或者node环境将所有JS检查一遍,检查是否有语法错误,注意并不会执行,这里是确保可执行,然后进行第二步:预编译

第二步:预编译

预备知识:变量提升

  首先要理解函数声明整体提升,变量 声明提升。这里要注意变量的提升,一般我们声明一个变量都是

var a = 1;
console.log(a) //1

//但实际上拆分成了两步,真正执行是这样的

var a;         // 这一步会提升到执行环境顶部
a = 1;
console.log(a) //1

如果将console.log放a前面会打印出undefined


console.log(a) //undefined
var a = 1;

// 实际上函数会按照下面步骤执行
// 因为变量的声明提升了,但是赋值并没有提升

var a;
console.log(a); // 这里a已经定义了,但没有赋值
a = 1;

预编译步骤:

1、预编译的时候会创建一个AO对象(Activation Object)执行上下文;

2、找形参和变量声明,将形参和变量作为AO对象的属性名,值为undefined;

3、将形参和实参统一;

4、在函数体里找函数声明,值赋给函数体

注意: AO按如下顺序填充

  • 函数参数(若有传参, 会被赋值, 若未传参, 初始化值为undefined) 优先级第二
  • 函数声明(若发生命名冲突, 会覆盖) 优先级最高
  • 变量声明(初始化变量值为undefined, 若发生命名冲突, 会忽略) 优先级第三

具体的步骤:

0:函数的在运行的瞬间,生成一个活动对象(Active Object)就是所谓的AO

1:分析参数

      1-1:函数接收参数,添加到AO的属性上面,值全部都是undefine,如AO.age=undefine

      1-2:接收实参,形成AO对应的属性值

2:分析变量声明,如var age,

     2-1:如果AO上还没有age属性,则添加AO 属性,值是undefine

     2-2:如果AO 上面已经有了age属性,则不做任何操作。

3:分析函数的声明,如果funcion foo(){},

3-1: 则把函数赋给AO.fooo,如果数据属性已经存在,则要被现在的新的值覆盖

最后开始按优先级赋值

举个例子:

function fn (a) {
  console.log(a)
}

fn(10)   // 10

function fn (a) {
  var a = 11
  console.log(a)
}

fn(10)   // 11

// 因为变量声明的优先级比参数的优先级高,所以a=11
function fn (a) {
  console.log(a)
  var a = 11
  function a () {
    console.log('我优先级最高')
  }
}

fn(10)   // [Function: a]


// 函数声明优先级最高
function fn (a) {
  var a = 11
  function a () {
    console.log('我优先级最高')
  }
  console.log(a)
}

fn(10)   // 11


// 注意,与上一段代码不同的是,在a被打印出来之前,
// a 经历的成长是:
// 1.形参a传过来,AO对象创造属性 AO.a = undefinded
// 2.结合实参,AO.a = 10
// 3.变量声明,它本应该在AO对象内创造 a 属性并赋值为undefinded,但a属性已经存在,不做改动
// 4.遇到函数声明,a 被赋值为一个函数体,即由 a = 10 变为 a = Function
// 5.开始执行函数,遇到 var a = 11 这一句,a 被赋值为 11,即 a = Function 变为 a = 11

2.然后就到了函数的执行阶段, 此阶段当前函数中使用到的所有变量和函数声明都会从当前函数的[[Scope]]作用域链中查找, 根据作用域链中对象的位置首先会查找当前函数的AO对象, 如果没有再查找上层对象, 最后找到全局对象, 如果都没有则会报错(变量未定义).

    原文作者:guolinengineer
    原文地址: https://blog.csdn.net/guolinengineer/article/details/84984498
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。