02-javascript函数执行过程(超详细)作用域链

958 阅读4分钟

coderwwh w:what是什么? w:why为什么? h:how怎么样? 本文重点:全局代码执行—函数

是什么

首先要了解一些概念

执行上下文

上篇文章说到js的执行上下文栈 那么执行上下文 和 执行上下文栈 有什么关系?

执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JS 引擎解析到代码的时候,就会先做一些执行前的准备工作,这个 “准备工作” ,就叫做 "执行上下文(execution context 简称 EC)" 或者也可以叫做执行环境

也就是说--》执行上下文 是 环境

js引擎内部有一个执行上下文栈(Execution Context Stack,简称ECS

它是用于执行代码的调用栈

那么现在它要执行谁呢?执行的是全局的代码块:GEC会 被放入到ECS中 执行;

GEC被放入到ECS中里面包含两部分内容:

  • 第一部分:在代码执行前,在parser转成AST的过程中,会将全局定义的变量、函数等加入到GlobalObject中,但是并不会赋值;这个过程也称之为变量的作用域提升(hoisting)

  • 第二部分:在代码执行中,对变量赋值,或者执行其他的函数;


分类

  • 全局 创建一个全局对象。2. 将 this 指针指向这个全局对象。

  • 函数 每个函数被调用,都会创建一个

  • eval函数 一般不用

变量对象(variable object 简称 VO

变量对象(Variable Object缩写为VO)是一个与执行上下文相关的特殊对象,存储了在上下文中定义的变量和函数声明

变量对象(Variable object)是说JS的执行上下文中都有个对象用来存放执行上下文中可被访问但是不能被delete的函数标示符、形参、变量声明等。它们会被挂在这个对象上,对象的属性对应它们的名字对象属性的值对应它们的值但这个对象是规范上或者说是引擎实现上的不可在JS环境中访问到活动对象

每个执行环境文都有一个表示变量的对象——变量对象,全局执行环境的变量对象始终存在,而函数这样局部环境的变量,只会在函数执行的过程中存在,在函数被调用时且在具体的函数代码运行之前,JS 引擎会用当前函数的参数列表arguments)初始化一个 “变量对象” 并将当前执行上下文与之关联 ,函数代码块中声明的 变量函数 将作为属性添加到这个变量对象上。

活动对象(activation object 简称 AO

不太好解释

为什么有这个?

其实我觉得要理解为什么这样设计才是最重要的,但是我不知道为什么要有AO,VO,GO...可能若干年后,才会理解吧?

全局代码执行顺序(怎么样执行?

图片.png 执行之前,编译阶段,创建GO(全局对象 图片.png 编译阶段,确定全局里面有哪些变量,把这些变量添加到全局对象里面,只加进去,值都是undefined

当要编译完了,开始执行,创建GEC,把这个东西放到调用栈里,让它进行执行 图片.png 比如要执行var name = "wwh",就回去VO里进行查找,这时VO就是GO,并且进行赋值,

本文重点:全局代码执行—函数

var name = "wwh"

foo()
function foo(){
  console.log(m)
  var m = 10
  var n = 20
  console.log("foo")
}

编译:执行之前,创建全局对象

var GlobalObject = {
  String: "类",
  window: GlobalObject,
  name: undefined,
  foo:0xa00
}

这个函数的值,不是undefined,

会创建另外一个对象,是函数对象 图片.png 这时候,编译完成

然后开始执行foo()

图片.png

会把函数,放到ECStack执行上下文栈中

不是直接把0xa00放进去,会再创建一个函数执行上下文(自动创建,有了之后也不会立马执行,执行之前,会创建AO对象,

图片.png

函数执行完后,函数执行上下文弹出调用栈

作用域链(面试题

图片.png

作用域链,在函数执行上下文中就确定了,也就是说,作用域链和函数它之后在哪里调用没有关系

看这样一道面试题

var name = "wwh"
function foo(){
    console.log(name)
}
function bar(){
    var name = "bar name"
    foo()
}
bar()

输出wwh,因为作用域链在创建的时候,就已经确定了

函数嵌套如何执行

foo(123)
function foo(num) {
  console.log(m)
  var m = 10
  var n = 20
  function bar() {
     console.log(name)
  }
  bar()
}

图片.png

函数调用函数

var message = "Hello Global"
function foo() {
  console.log(message)
}
function bar() {
  var message = "Hello Bar"
  foo()
}
bar()

图片.png