亲宝软件园·资讯

展开

JavaScript 变量对象

小宝的挖机 人气:0

前言

在上节《深入 JavaScript 执行上下文栈——Web 前端进阶系列第三节》我们讲到,JavaScript 引擎执行一段可执行代码时,会创建对应的执行上下文。

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

今天我们来重点讲解变量对象。

变量对象

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

执行上下文分为两种:全局上下文和函数上下文,接下来我们来分别讲解这两种上下文的变量对象。

全局上下文中变量对象

全局上下文中的变量对象是全局对象。

下面我们来了解一下全局对象,在 W3school 中的介绍有:

字面上大家理解起来可能比较抽象,接下来我们结合具体例子作进一步讲解。

console.log(this); // window
console.log(this === window); // true
// 声明的变量成为了全局对象的属性
var a = 1;
console.log(this.a); // 1

// 声明的函数成为了全局对象的属性
function b() {}
console.log(this.b); // function b
// 使用全局对象访问全局属性 Math,它是一个对象,它拥有 random 方法。
console.log(this.Math.random()); // 打印一个随机数
// 这里的 Math 是非限定性的函数名
console.log(Math.random()); // 打印一个随机数
console.log(this instanceof Object); // true
console.log(this.window === this); // true

函数上下文中的变量对象

在函数上下文中,我们用活动对象(activation object, AO)来表示变量对象。

活动对象和变量对象其实是一个东西,只是变量对象是规范上的或者说是引擎实现上的,不可在 JavaScript 环境中访问,只有到当进入一个执行上下文中,这个执行上下文的变量对象才会被激活,所以才叫 activation object,而只有被激活的变量对象,也就是活动对象,各种属性和方法才能被访问。

活动对象是在进入函数上下文时被创建的,它有函数的 arguments 属性作为初始化属性。arguments 属性的值就是 Arguments 对象。

执行过程

函数上下文的代码执行过程共分成两个阶段,分别是:预编译和执行。

预编译

我们来看个例子:

function foo(a) {
  var b = 2;
  function c() {}
  var d = function() {};

  b = 3;
}

foo(1);

这个函数在预编译完成后,AO 会变为:

AO = {
    arguments: {
        0: 1,
        length: 1
    },
    a: 1,
    b: undefined,
    c: reference to function c(){},
    d: undefined
}

代码执行

在代码执行阶段,会顺序执行代码。根据代码,修改变量对象的值。

上面的例子当代码执行完,AO 会变为:

AO = {
    arguments: {
        0: 1,
        length: 1
    },
    a: 1,
    b: 3,
    c: reference to function c(){},
    d: reference to FunctionExpression "d"
}

总结

至此,变量对象的创建过程我们就介绍完了,我们来做个总结:

练习题

来看下面两端代码,分别会打印什么?

function foo() {
  console.log(a);
  a = 1;
}

foo();
function bar() {
  a = 1;
  console.log(a);
}
bar();

第一段会报错:Uncaught ReferenceError: a is not defined。

第二段会打印:1。

因为第一段代码 a 没有变量声明,所以函数执行上下文的 AO 中没有 a 变量的定义,此时 AO 的值是:

AO = {
    arguments: {
        length: 0
    }
}

执行打印时,在函数执行上下文的 AO 中没有找到 a 变量的定义,然后就会去全局上下文中找,发现全局也没有,所以就会报未定义的错。

第二段代码,没有使用 var 关键字声明的变量会成为全局对象的属性,所以执行打印时,会从全局对象找到 a 的值,所以会打印 1。

console.log(foo);

function foo() {}

var foo = 1;

会打印 foo 函数,而不是 undefined。

因为在预编译的第 4 步,会寻找函数声明,值为函数体,也就是函数声明会覆盖变量声明。

加载全部内容

相关教程
猜你喜欢
用户评论