Please enable Javascript to view the contents

从头学习js-4-变量对象

 ·  ☕ 3 分钟

这个系列是我读冴羽老师博客的感悟,
加入了个人的解读和练习题的解答

上篇说到,当javascript代码执行一段可执行代码(executable code)时,会创建对应的执行上下文(execution context)

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

  • 变量对象(Variable object, VO)
  • 作用域链(Scope chain)
  • this

本文主要讲执行上下文中的变量对象


变量对象

变量对象是与执行上下文相关的数据作用域,储存了在上下文中定义的变量和函数声明

因为不同执行上下文的变量对象稍有不同,这里分全局上下文下的变量对象和函数上下文下的变量对象来讨论。

全局上下文的变量对象就是全局对象,是全局变量的宿主。
在浏览器中,全局中的this和window都指向全局变量

函数上下文中的变量对象称为活动对象(activation object,AO)
活动对象就是变量对象,只是函数上下文中的变量对象只有函数代码在执行到被激活时才能被访问到,
活动对象就是在进入函数上下文时被创建的,它通过函数的arguments属性初始化。


执行上下文生命周期:

  1. 创建执行上下文阶段
    创建变量对象,建立作用域,以及明确this的指向
  • 变量对象包括:

    1. 函数所有形参
    • 由名称和对应值组成的一个变量对象的属性被创建
    • 没有实参,属性值设为undefined
    1. 函数声明(函数声明优先于变量声明)
    • 由名称和对应值(函数对象(function-object))组成的一个变量对象的属性被创建
    • 如果变量对象已经存在相同名称的属性,则完全替换这个属性
    1. 变量声明
    • 由名称和对应值(undefined)组成的一个变量对象的属性被创建
    • 如果变量名称和已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性
  1. 执行代码阶段
    创建上下文后,开始执行代码,

例子:

1
2
3
4
5
6
7
8
9
function foo(a) {
  var b = 2;
  function c() {}
  var d = function() {};

  b = 3;
}

foo(1)

在进入执行上下文后,此时的AO为

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
AO = {
  //AO通过函数的arguments初始化,是一个伪数组
  arguments: {
    0: 1,
    length: 1
  },
  
  //函数所有形参 由名称和对应值组成的一个变量对象的属性被创建
  a: 1,

  //变量声明 名称和对应值(undefined)组成的一个变量对象的属性被创建
  b: undefined,

  //函数声明 由名称和对应值(函数对象(function-object))组成的一个变量对象的属性被创建
  c: reference to function c(){}, 
  
  //同上变量声明
  d: undefined
}

函数执行后:
按顺序执行代码,初始化变量和给变量赋值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
AO = {
  arguments: {
      0: 1,
      length: 1
  },
  a: 1,
  b: 3,
  c: reference to function c() {},
  d: reference to FunctionExpression "d"
}

关于声明变量和函数时的补充:

这里认为声明变量和函数都有三个阶段:
1.创建create
2.初始化initialize(声明时首次初始化不同于第三步的assign)
3.赋值assign

关于声明语法的结论是:
function 的「创建」「初始化」和「赋值」都被提升了。
var 的「创建」和「初始化」都被提升了。
let 的「创建」过程被提升了,但是初始化没有提升,拥有块级作用(暂时性死区)。
const 只有创建和初始化,没有「赋值」,「创建」过程被提升了,拥有块级作用(暂时性死区)

通常认为const不可变是片面的,
首先const必须初始化,且在栈中储存的值不可修改,
但当const声明的是引用类型时,堆中的储存值可以改变
如:

1
2
3
const obj = {name: 'Neo', age: 20}
obj.age = 25
console.log(obj) //{name: 'Neo', age: 25}

如果不通过关键词var let等声明变量,AO中不会创建对应该变量的key-value

但是当这个变量被赋值assign的时候会创建变量对象到VO中


more 参考资料:

分享

Llane00
作者
Llane00
Web Developer