关于javascript中的 执行上下文和对象变量

什么是执行上下文

当浏览器的解释器开始执行我们的js代码的时候,js代码运行所处的环境可以被认为是代码的执行上下文,执行上下文(简称-EC)是ECMA-262标准里的一个抽象概念,用于同可执行代码(executable code)概念进行区分。一般来讲,执行上下文可以在以下三种情况产生:

1. 全局上下文(globalContext)   2. function 内部 3. Eval code.

看个例子,包含全局和function内部上下文

  

紫色框内表示全局的执行上下文,同时内部会有3个不同的Function context, function context可以有多个,但是全局上下文只有一个,并且当解释器开始执行代码的时候就会创建全局上下文并进入。 我们可以创建任意多个Function context,声明一个方法并执行的时候会自动创建该function context,同时创建一块区域,在该区域内创建的变量或其他声明不直接被外部context所访问。

执行上下文堆栈

浏览器内部js解释器是按照单线程的方式实现,意味着内部只能同时在做一件事情,其他的调用都会在被称为执行堆栈的地方排队。看下面的图:

  

当浏览器加载js的时候,就会默认进入全局上下文,如果全局代码中开始执行function,则会创建一个新的execution context,并把该execution context push到栈顶。

如果在function里面又调用内部function,则会执行相同的操作,创建新的execution context,并push到栈顶。看例子:

(function foo(i){
    if(i === 3){
        return;
       }else{
     foo(++i);
    }
}
)(0)

  

foo会执行三次,每次执行会生成新的execution context,执行结束则自动出栈。

执行上下文的细节

现在我们知道伴随着function的调用,都会产生一个新的context,在解释器内部,大致分为两个阶段:

Stage I:创建阶段(function被调用,但是在开始执行任何代码之前)

  创建阶段大致做了以下几件事情:

  ①:生成变量对象。该阶段把所有的声明都以key-value的形式提取出来,包括 函数的形参(value为实参的值),function arguments,内部function名(value是对内部function的引用),function内的变量声明(value值统一为undefined)。

  ②:创建作用域链。作用域链包含该上下文中的变量对象和所有父上下文的变量对象,用于变量查找)

  ③:给this赋值。关于this的理解,参考《对javascript this的理解

Stage II:执行阶段(给变量赋值,逐步执行)

理解了以上两个执行阶段后,我们可以大体描绘一下执行上下文中有哪些东西,可以用一个带有3个属性的对象来表示:

executionContextObj = {
    scopeChain: { /* variableObject + all parent execution context‘s variableObject */ },
    variableObject: { /* function arguments / parameters, inner variable and function declarations */ },
    this: {}
}

对象变量和活动对象 Variable/Activation Object[VO/AO]

executionContextObj在function每次被调用的时候创建,在上文提到的StageI阶段,解释器会对function进行扫描,包括function的arguments, 参数,内部变量声明和内部function声明,扫描的结果会被放到 我们称为 对象变量的对象中(variable object).

看例子:

var a = 10;

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

test(30);

以上代码对应的变量对象应该为:

VO(global context) = {
    a: 10,
    test: <reference to function>
}

VO(test function context) = {
    x:30,
    b:20
}

具体分为两种,

全局上下文中的对象变量

首先,我们要给全局对象一个明确的定义:

全局对象(Global object) 是在进入任何执行上下文之前就已经创建了的对象;这个对象只存在一份,它的属性在程序中任何地方都可以访问,全局对象的生命周期终止于程序退出那一刻。

全局对象初始创建阶段将Math、String、Date、parseInt作为自身属性,等属性初始化,同样也可以有额外创建的其它对象作为属性(其可以指向到全局对象自身)。例如,在DOM中,全局对象的window属性就可以引用全局对象自身(当然,并不是所有的具体实现都是这样):

global = {  Math: <...>,  String: <...>  ...  ...  window: global //引用自身};

当访问全局对象的属性时通常会忽略掉前缀,这是因为全局对象是不能通过名称直接访问的。不过我们依然可以通过全局上下文的this来访问全局对象,同样也可以递归引用自身。例如,DOM中的window。综上所述,代码可以简写为:

String(10); // 就是global.String(10);

// 带有前缀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); // 直接访问,在VO(globalContext)里找到:"test"

alert(window[‘a‘]); // 间接通过global访问:global === VO(globalContext): "test"alert(a === this.a); // true

var aKey = ‘a‘;alert(window[aKey]); // 间接通过动态属性名称访问:"test"

 函数上下文中的变量对象

在函数执行上下文中,VO是不能直接访问的,此时由活动对象(activation object,缩写为AO)扮演VO的角色。

VO(functionContext) === AO;

活动对象是在进入函数上下文时刻被创建的,它通过函数的arguments属性初始化。arguments属性的值是Arguments对象:

AO = {  arguments: <ArgO>};

Arguments对象是活动对象的一个属性,它包括如下属性:

  1. callee — 指向当前函数的引用
  2. length — 真正传递的参数个数
  3. properties-indexes (字符串类型的整数) 属性的值就是函数的参数值(按参数列表从左到右排列)。 properties-indexes内部元素的个数等于arguments.length. properties-indexes 的值和实际传递进来的参数之间是共享的。

例如:

function foo(x, y, z) {

  // 声明的函数参数数量arguments (x, y, z)  alert(foo.length); // 3

  // 真正传进来的参数个数(only x, y)  alert(arguments.length); // 2

  // 参数的callee是函数自身  alert(arguments.callee === foo); // true

  // 参数共享

  alert(x === arguments[0]); // true  alert(x); // 10

  arguments[0] = 20;  alert(x); // 20

  x = 30;  alert(arguments[0]); // 30

  // 不过,没有传进来的参数z,和参数的第3个索引值是不共享的

  z = 40;  alert(arguments[2]); // undefined

  arguments[2] = 50;  alert(z); // 40

}

foo(10, 20);

 综上,来看一个比较综合的例子:

function foo(i) {
    var a = ‘hello‘;
    var b = function privateB() {

    };
    function c() {

    }
}

foo(22);

foo被调用,StageI阶段:

foo executionContextObj = {
    scopeChain: { ... },
    varaible object :{
        arguments:{
            length:1,
            callee : foo,//对调用foo的引用
            0:22
        }
        i : 22,
        c : <reference function()>,
        a : undefined,
        b : undefined
    },
    this : global

}

Stage II :

fooExecutionContext = {
    scopeChain: { ... },
    variableObject: {
        arguments: {
            0: 22,
            callee:foo
            length: 1
        },
        i: 22,
        c: pointer to function c()
        a: ‘hello‘,
        b: pointer to function privateB()
    },
    this: global
}

关于javascript中的 执行上下文和对象变量,布布扣,bubuko.com

时间: 2024-08-02 07:01:07

关于javascript中的 执行上下文和对象变量的相关文章

JavaScript进阶之执行上下文和执行栈

js引擎的执行过程 执行上下文和执行栈属于js引擎的执行过程的预编译阶段. 执行上下文(Execution Context) 执行上下文是当前 JavaScript 代码被解析和执行时所在环境的抽象概念.可以理解为当执行代码时做的准备工作. 执行上下文按照运行环境被分成三类: 全局执行上下文(JS代码加载完毕后,进入代码预编译即进入全局环境) 函数环境执行上下文(函数调用执行时,进入该函数环境,不同的函数则函数环境不同) eval执行上下文(不建议使用,会有安全,性能等问题) 对于每个执行上下文

【JS】JavaScript中的执行环境与作用域

JavaScript中的执行环境定义了变量或函数有权访问的数据(每个函数都有自己的执行环境),全局执行环境是最外围的执行环境,在浏览器中,全局执行环境就是window对象,所以所有的全局变量和函数都是作为window对象的属性和方法创建的.当某一个执行环境中所有代码执行完成后,该环境就被销毁,保存在其中的变量和函数也将被销毁,全局执行环境在关闭网页或浏览器时才被销毁. 当代码在一个环境中执行时,会创建变量对象的一个作用域链(保证对执行环境有权访问的变量和函数的有序访问),如果环境是函数,将其活动

javaScript中eval()方法转换json对象

原文:javaScript中eval()方法转换json对象 <script language="javascript"> var user = '{name:"张三",age:23,'+ 'address:{city:"青岛",zip:"266071"},'+ 'email:"[email protected]",'+ 'showInfo:function(){'+ 'document.wri

Javascript中的执行环境及作用域

执行环境(exectution context)定义了变量或函数有权访问的其他数据,决定了它们各自的行为.每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中.虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它. 全局执行环境是最外围的一个执行环境.在web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的.某个执行环境中的所有代码执行完毕后,该环境

Javascript中的&quot;函数是第一类对象(first-class object)&quot;

本身这句话很好解释,函数有两个主要特点,援引自 陈新 译的<JavaScript模式>: 1.函数是第一类对象: 函数可以在运行时动态创建,还可以在程序执行过程中创建. 函数可以分配变量,可以将它们的引用复制到其他变量,可以被扩展,此外,除少数特殊情况外,函数还可以被删除. 可以作为参数传递给其他函数,并且还可以有其他函数返回. 函数可以有自己的属性和方法. 2.函数提供了作用域 在JavaScript中,没有使用花括号{}语法来定义局部变量的作用域,也就是说,块并不能创建作用域.这也就意味着

JavaScript 中的执行环境、作用域(scope)以及变量提升(hoisting)

先看下面一段代码: var a = 0; alert("1st alert : a = " + a); function fun(){ alert("2nd alert : a = " + a); var a = 1; setTimeout(function(){ alert("3rd alert : a = " + a); a = 2; },1000); a = 3; setTimeout(function(){ alert("4th

ES6新特性:Javascript中的Map和WeakMap对象

Map对象 Map对象是一种有对应 键/值 对的对象, JS的Object也是 键/值 对的对象 : ES6中Map相对于Object对象有几个区别: 1:Object对象有原型, 也就是说他有默认的key值在对象上面, 除非我们使用Object.create(null)创建一个没有原型的对象: 2:在Object对象中, 只能把String和Symbol作为key值, 但是在Map中,key值可以是任何基本类型(String, Number, Boolean, undefined, NaN..

Javascript中的函数(Function)与对象(Object)的关系

今天我们来尝试理解Function和Object.因为这个里面有些人前期可能会搞糊涂.他们之间到底是什么关系.当然也不除外当初的我. 注意:官方定义: 在Javascript中,每一个函数实际上都是一个函数对象. 我们先来看最简单的两个代码,也是最容易理解的. function fn(){} var obj = {} console.log(fn instanceof Function)//true console.log(obj instanceof Object)//true console

JavaScript中的Document文档对象

Document文档对象是JavaScript中window和frames对象的一个属性,是显示于窗口或框架内的一个文档.描述当前窗口或指定窗口对象的文档.它包含了文档从到的内容. 用法:document (当前窗口) 或 <窗口对象>.document (指定窗口) 属性: document.title //设置文档标题等价于HTML的定义的文字.在 Netscape 里本属性不接受赋值. fgColor 指标记的 text 属性所表示的文本颜色. bgColor 指标记的 bgcolor