资讯专栏INFORMATION COLUMN

ECMA-262-3详解(2)变量对象

MAX_zuo / 1518人阅读

摘要:不同执行上下文中的变量对象对于所有的执行上下文类型,变量对象的一些操作比如变量实例化和行为是共通的。从这点看,将变量对象看作是抽象的基础的东西很便利。全局上下文的变量对象现在,应该先给出全局对象的定义。

原文地址

作者的话

有很多文章已经对ECMAScript的核心概念做了详尽解读。本系列文章翻译自Dmitry Soshnikov的个人网站,相信不少人已经看过原文或者译文。原文简洁易懂并且严谨,条理清晰地阐明了所有JavaScript开发者不得不深入理解的ECMAScript核心概念。重复翻译的原因主要是为了个人收藏、整理之用。初次翻译,技巧拙劣,如有不足,请不吝赐教。

正文

介绍

数据声明

不同执行上下文中的变量对象

全局上下文中的变量对象

函数上下文中的变量对象

处理上下文代码的阶段

进入执行上下文

代码执行

关于变量

实现的特点:__parent__属性

结论

介绍

我们总是在程序中声明函数和变量,然后成功地用作构建我们的系统。但是,解释器怎样以及在哪里找到我们的数据(函数和变量)?当我们引用需要的对象的时候发生了什么?

许多ECMAScript开发者知道变量和执行上下文紧密相关。

var a = 10; // variable of the global context
 
(function () {
  var b = 20; // local variable of the function context
})();
  
alert(a); // 10
alert(b); // "b" is not defined

同时,许多程序员也知道当前版本(ES6之前,译者注)的标准的独立作用域是通过“函数”代码类型的执行上下文创建的。比如,和C/C++相反,ECMAScript中的for循环块不会创建本地上下文。

for (var k in {a: 1, b: 2}) {
  alert(k);
}
  
alert(k); // variable "k" still in scope even the loop is finished

让我们看看当我们声明数据时的所发生的细节。

数据声明

如果变量和执行上下文相关,那么应该知道变量的数据存在哪里以及如何获取它们。这个机制被称为变量对象

变量对象(简称:VO)是一个与执行上下文相关的特殊对象,它存储了在上下文中声明的:

变量

函数声明

函数形参

注意,在ES5中,变量对象的概念已经被词法环境模式取代,可以在适当的章节找到它的详细描述。

示意性的举个例子,可以将变量对象表示成一个普通的ECMAScript对象:

VO = {};

正如我们所说,VO是执行上下文的属性:

activeExecutionContext = {
  VO: {
    // context data (var, FD, function arguments)
  }
};

只允许在全局上下文(全局对象就是变量对象的地方)中,对变量间接引用(通过VO的属性名)。对于其他上下文,对VO对象的直接引用是不可能的,这纯粹是实现机制。

当我们声明了一个变量或函数,除了使用我们的变量的名字和值创建VO的新属性,没别的了。
比如:

var a = 10;
 
function test(x) {
  var b = 20;
};
 
test(30);

相应的变量对象是这样:

// Variable object of the global context
VO(globalContext) = {
  a: 10,
  test: 
};
  
// Variable object of the "test" function context
VO(test functionContext) = {
  x: 30,
  b: 20
};

但是在实现层面(以及规范)中,变量对象是一个抽象的概念。物理上,在具体的执行上下文中,VO被叫做不同的名称,有不同的初始结构。

不同执行上下文中的变量对象

对于所有的执行上下文类型,变量对象的一些操作(比如变量实例化)和行为是共通的。从这点看,将变量对象看作是抽象的基础的东西很便利。函数上下文也可以定义与变量对象相关的额外内容。

AbstractVO (generic behavior of the variable instantiation process)
 
  ║
  ╠══> GlobalContextVO
  ║        (VO === this === global)
  ║
  ╚══> FunctionContextVO
           (VO === AO,  object and  are added)

我们详细解读一下。

全局上下文的变量对象

现在,应该先给出全局对象的定义。

全局对象是在进入任何执行上下文前创建的对象;这个对象仅存在一份,它的属性可以在程序的任何位置访问到,全局对象的生命周期伴随着程序结束而结束。

在创建时,全局对象使用诸如:Math、String、Date、parseInt等初始化,也可以使用附加对象初始化,附加对象可以是全局对象本身的引用--比如在BOM中,全局对象的window属性引用全局对象(不是在所有的实现中都是如此)。

global = {
  Math: <...>,
  String: <...>
  ...
  ...
  window: global
};

当引用全局对象的属性,前缀往往可以省略,因为全局对象不能通过名字直接访问到。然而,在全局上下文中可以通过this值访问到它,也可以通过对它的递归引用访问到它,比如BOM中的window,因此可以简写:

String(10); // means global.String(10);
 
// with prefixes
window.a = 10; // === global.window.a = 10 === global.a = 10;
this.b = 20; // global.b = 20;

所以回到全局上下文的变量对象,这里变量对象就是全局对象本身:

VO(globalContext) === global;

很有必要理解这个事实,由于这个原因,在全局上下文中声明一个变量,我们可以通过全局对象的属性间接访问它(比如,当变量名事先未知时):

var a = new String("test");
 
alert(a); // directly, is found in VO(globalContext): "test"
 
alert(window["a"]); // indirectly via global === VO(globalContext): "test"
alert(a === this.a); // true
  
var aKey = "a";
alert(window[aKey]); // indirectly, with dynamic property name: "test"
函数上下文的变量对象

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96863.html

相关文章

  • ECMA-262-3详解(1)执行上下文

    摘要:逻辑上讲,活跃的执行上下文集合组成了一个栈。栈底是全局上下文,栈顶是当前活跃执行上下文。举个例子,我们将执行上下文定义成一个数组。一个抛出但是没有捕获的异常可能导致退出一个或多个执行上下文代码代码更加复杂。 原文地址 作者的话 有很多文章已经对ECMAScript的核心概念做了详尽解读。本系列文章翻译自Dmitry Soshnikov的个人网站,相信不少人已经看过原文或者译文。原文简洁...

    tinyq 评论0 收藏0
  • JavaScript中的执行上下文

    摘要:如果在全局代码中调用函数,程序的顺序流进入被调用的函数,创建新的执行上下文并将其推送到执行堆栈的顶部。每次调用函数时,都会创建一个新的执行上下文。 翻译:疯狂的技术宅链接:http://davidshariff.com/blog/... 本文首发微信公众号:jingchengyideng欢迎关注,每天都给你推送新鲜的前端技术文章 在这篇文章中,我将深入探讨JavaScript的最...

    cfanr 评论0 收藏0
  • 执行上下文(执行环境)-Chapter1

    摘要:堆栈结构的底部是全局执行上下文,顶部是当前执行上下文。不同的执行上下文切换时堆栈会发生改变译论及代码类型时,在某些时候可能也意味着执行上下文。函数体中代码执行完后,只剩全局上下文直到程序结束译代码更有意思。 第一次翻译,希望各位多多包涵,有错误处还望指出,欢迎提出建议。 Chapter 1.Execution Contexts Introduction (介绍) Definitio...

    elisa.yang 评论0 收藏0
  • 深入理解JavaScript系列4:立即调用的函数表达式

    摘要:前言大家学的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行。其实,前面两个例子里的变量,也可以换成,因为和外面的不在一个作用于,所以不会出现问题,这也是匿名函数闭包的威力。 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行。 在详细了解这个之前,我们来谈了解一下自执行这个叫法,本文对这个功能的叫法也不一定完全对...

    roadtogeek 评论0 收藏0
  • JavaScript中的函数

    摘要:然后最后一步就是从父作用域链中将该特殊对象删除,整个过程的伪代码如下注意这里,该属性不能删除,只读。 起因是我在逛sf的时候看到了一个人的提问: 为什么将函数c赋值给变量b,在函数体里面,给c赋值,为什么会失败?也就是这代码执行时为什么c打印出来的不是3 var b = function c () { a=1, b=2, c=3; console.log(a); ...

    coolpail 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<