Javascript中的执行上下文

1. Javascript中的执行上下文类型

Javascript中有三种执行上下文类型:全局执行上下文、函数执行上下文和Eval函数执行上下文。

全局执行上下文是在代码执行之前创建的,而函数执行上下文是在函数调用时创建的。Eval函数执行上下文是在代码执行期间由eval()函数创建的。

下面分别介绍这三种执行上下文类型。

1.1 全局执行上下文

全局执行上下文是默认的执行上下文,它在代码执行之前创建,当页面加载完成后便会创建。

代码执行过程中,只会存在一个全局执行上下文,全局执行上下文中的变量、函数等都是全局可访问的。

下面是一个全局执行上下文的示例:

var a = 1;

function foo() {

console.log('hello');

}

在代码执行之前,就已经创建了全局执行上下文,此时全局执行上下文中包含:

{

VO: {

a: 1,

foo:

},

Scope: [global]

}

VO是variable object的简称,代表变量对象,表示执行上下文中的变量、函数等信息。

Scope代表作用域,全局执行上下文的作用域为全局作用域。

1.2 函数执行上下文

函数执行上下文是在函数调用时创建的,每次调用函数都会创建新的函数执行上下文。

函数执行上下文中包含函数的参数、变量、函数等信息。

下面是一个函数执行上下文的示例:

function foo(a, b) {

var c = a + b;

console.log(c);

}

foo(1, 2);

在调用foo函数时,会创建一个新的函数执行上下文,此时该函数执行上下文中包含:

{

VO: {

a: 1,

b: 2,

c: undefined,

arguments: {0: 1, 1: 2, length: 2},

foo:

},

Scope: [foo's scope, global]

}

arguments是一个类数组对象,包含了函数的参数信息。

1.3 Eval函数执行上下文

Eval函数执行上下文是在代码执行期间由eval()函数创建的执行上下文。

由于eval()函数会执行传入的字符串代码,所以Eval函数执行上下文中包含了该字符串中的变量、函数等信息。

下面是一个Eval函数执行上下文的示例:

var a = 1;

eval('var b = 2; console.log(a + b);');

在执行eval()函数时,会创建一个新的Eval函数执行上下文,此时该函数执行上下文中包含:

{

VO: {

b: 2

},

Scope: [global]

}

可以看到,Eval函数执行上下文中只包含了代码中定义的变量b,而全局作用域中的其他变量并没有包含在其中。

2. 执行上下文的创建

在Javascript中,执行上下文的创建分为两个阶段:

创建阶段

代码执行阶段

2.1 创建阶段

在创建阶段,Javascript会先创建VO,然后将VO和作用域链等信息添加到执行上下文中,最后创建this。

下面是一个创建阶段的示例:

function foo() {

var a = 1;

console.log(a);

}

foo();

在调用foo函数时,会经过执行上下文的创建阶段,此时执行上下文中包含:

{

VO: {

a: undefined,

foo:

},

Scope: [foo's scope, global]

}

可以看到,在创建阶段中,Javascript先创建了VO,然后将VO添加到执行上下文中,此时a的值为undefined。

2.2 代码执行阶段

在代码执行阶段,Javascript会按照代码的顺序执行代码,并更新执行上下文中的变量等信息。

下面是一个代码执行阶段的示例:

function foo() {

var a = 1;

console.log(a);

}

foo();

在调用foo函数时,会先经过执行上下文的创建阶段,然后进入代码执行阶段,在代码执行阶段中,Javascript会按照代码的顺序执行代码:

{

VO: {

a: undefined,

foo:

},

Scope: [foo's scope, global]

}

{

VO: {

a: 1,

foo:

},

Scope: [foo's scope, global]

}

可以看到,在代码执行阶段中,Javascript会先执行var a = 1;语句,然后输出a的值。

3. 执行上下文的销毁

当Javascript完成代码的执行之后,会销毁当前的执行上下文,此时执行上下文中的变量、函数等都会被销毁。

下面是一个执行上下文销毁的示例:

function foo() {

var a = 1;

console.log(a);

}

foo();

在调用foo函数时,会先创建一个新的执行上下文,然后在代码执行完毕后销毁该执行上下文,此时执行上下文中的变量a也被销毁了。

4. 执行上下文的作用域

执行上下文的作用域是指变量、函数等的可访问范围,在Javascript中,执行上下文的作用域是由作用域链来实现的。

作用域链是由多个执行上下文对象组成,每个执行上下文对象包含一个Scope属性,其中存储着它的外部执行上下文的引用。

下面是一个作用域链的示例:

var a = 1;

function foo() {

var b = 2;

console.log(a + b);

}

foo();

在调用foo函数时,会创建一个新的执行上下文,并将它的Scope属性指向全局执行上下文的变量对象。

这样在执行foo函数中的console.log(a + b)时,Javascript会先在foo函数的变量对象中查找变量b的值,如果找到则直接使用,否则就会沿着作用域链向上查找,直到找到全局执行上下文的变量对象并查找到变量a的值。

5. 执行上下文与this关键字

this关键字表示当前函数执行的上下文环境,在Javascript中,this的值是动态变化的,根据函数的调用方式不同,this的值也不同。

下面介绍几种常见的函数调用方式及this的取值:

5.1 普通函数调用

当函数作为普通函数调用时,this的值指向全局对象。

function foo() {

console.log(this);

}

foo(); // 输出window对象

5.2 方法调用

当函数作为对象的方法调用时,this的值指向该对象。

var obj = {

name: 'John',

getName: function() {

console.log(this.name);

}

};

obj.getName(); // 输出John

5.3 构造函数调用

当函数通过new关键字作为构造函数调用时,this的值指向新创建的对象。

function Person(name, age) {

this.name = name;

this.age = age;

}

var p = new Person('John', 20);

console.log(p); // 输出{name: "John", age: 20}

5.4 apply/call调用

当函数通过apply、call等方法调用时,this的值可以通过传入的第一个参数来指定,如果没有传入参数,则指向全局对象。

function getName() {

console.log(this.name);

}

var obj = {

name: 'John'

};

getName.apply(obj); // 输出John

6. 小结

执行上下文是Javascript中重要的概念,理解它对于深入理解Javascript的运行机制非常有帮助。

Javascript中有三种执行上下文类型:全局执行上下文、函数执行上下文和Eval函数执行上下文。执行上下文的创建分为两个阶段:创建阶段和代码执行阶段。执行上下文的作用域是由作用域链来实现的。this关键字表示当前函数执行的上下文环境,在不同的函数调用方式下,this的值也不同。