hzzzzzzzq / Blog

这是我记录博客的地方,希望能多写一些技术博客,JS、ES、React、Vue等
14 stars 0 forks source link

深入理解JavaScript系列(6):执行上下文 #47

Open hzzzzzzzq opened 2 years ago

hzzzzzzzq commented 2 years ago

JavaScript 深入之执行上下文

在[《JavaScript 深入之执行上下文栈》]()中提到,当 JavaScript 代码执行代码时,就会创建一个执行上下文。

对于执行上下文,都有三个重要属性:

分别单独介绍了三个属性 - [《JavaScript 深入之变量对象》]()、[《JavaScript 深入之作用域链》]()、[《JavaScript 深入之 this》]()。

我们在上面的文章中,不止一次提到过执行上下文这个东西,然后每次都是分开介绍的,并不完全,现在我们就来整合一下执行上下文吧。

执行上下文 - 例子一

我们直接给出一个例子吧,然后来看看什么是执行上下文吧。

var name = 'hzq';
function checkName() {
  var name = 'hzzzzzzzq';
  function fn() {
    return name;
  }
  return fn();
}
console.log(checkName()); // hzzzzzzzq

执行过程

1. 执行全局代码,创建全局上下文,并压入执行上下文栈

ECStack = [globalContext];

2. 全局上下文初始化,同时创建 checkName 函数,保存作用域链到函数内部属性 [[scope]]

globalContext = {
  VO: [global],
  Scope: [globalContext.VO],
  this: globalContext.VO,
};
checkName.[[scope]] = [
  globalContext.VO
];

3. 执行 checkName 函数,创建函数上下文,并压入栈

ECStack = [checkNameContext, globalContext];

4. checkName 函数执行上下文初始化: | 这时候 fn 函数也被创建,保存 [[scope]]

checkNameContext = {
  AO: {
    arguments: {
      length: 0,
    },
    name: undefined,
    fn: reference to function fn() {}
  },
  Scope: [AO, globalContext.VO],
  this: undefined
};

// fn 函数保存 [[scope]]

fn.[[scope]] = [
  checkNameContext.AO, gloablContext.VO
]

5. 执行 fn 函数,创建上下文,压入栈

ECStack = [fnContext, checkNameContext, globalContext];

6. fn 函数执行上下文初始化

fnContext = {
  AO: {
    arguments: {
      length: 0,
    },
  },
  Scope: [AO, checkNameContext.AO, globalContext.VO],
  this: undefined,
};

7. fn 通过作用域链查找 name 属性,并返回

8. fn 函数指向完毕,出栈

ECStack = [checkNameContext, globalContext];

9. checkName 函数执行完毕,出栈

ECStack = [globalContext];

10. 继续执行其他全局代码,直到其他代码执行完毕,全局上下文出栈

执行上下文 - 例子二

var name = 'hzq';
function checkName() {
  var name = 'hzzzzzzzq';
  function fn() {
    return name;
  }
  return fn;
}
checkName()(); // hzzzzzzzq
// 等价于
let fn = checkName();
fn();

执行过程 - 变化点

我们直接来看看例子二与例子一的不同点。

5. checkName 函数执行完毕,出栈

ECStack = [globalContext];

6. 执行 fn 函数,创建上下文,压入栈

ECStack = [fnContext, globalContext];

7. fn 函数执行上下文初始化

fnContext = {
  AO: {
    arguments: {
      length: 0,
    },
  },
  Scope: [AO, checkNameContext.AO, globalContext.VO],
  this: undefined,
};

8. fn 函数执行完毕,出栈

9. 执行全局其他代码,执行完毕,全局上下文出栈

是不是很简单呢?