20151028 执行上下文环境
#
1. 什么是自由变量?
2. 上下文环境怎么产生的?什么时候产生的?
3. 压栈和出栈的顺序
一 执行上下文环境
在一段js代码真正运行之前,浏览器就已经做了一些”准备工作”,其中就包括对变量的声明,变量的赋值是在赋值语句执行的时候进行的.
1/ 变量
console.log(a); //输出: Uncaught ReferenceError: a is not definedconsole.log(a); //输出: undefined var a; console.log(a); //输出: undefined var a = 10;
2/ this
console.log(this); //输出: Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…}3/ 函数声名
console.log(f1); // function f1() { }
function f1() { } // 函数声名
说明:
“准备工作”中完成了那些工作:
1/ 变量: 变量的声明,默认赋值为undefined;
2/ this: 赋值
3/ 函数声明: 赋值
这三种数据的准备情况我们称之为”执行上下文”或者”执行上下文环境”.
函数中的变量:
如果在函数中,除了以上数据之外,还有其他数据,如:
function fn(x) {
console.log(arguments);
console.log(x);
}
fn(10);
//输出: [10]
10
说明:
函数每被调用一次,都会产生一个新的执行上下文环境,因为不同的调用可能就会有不同的参数.
var a = 10;
function fn() {
console.log(a); //a是自由变量
} //函数创建时,就确定了a要取值的作用域
function bar(f) {
var a = 20;
fn(); //输出"10",而不是"20"
}
bar(fn);
说明:
函数定义的时候,就已经确定了函数体内部变量的作用域.
总结:
全局的上下文环境数据内容
普通变量(包括函数表达式).如: var a = 10; | 声明(默认赋值为undefined) |
函数声名,如: function fn() {} | 赋值 |
this | 赋值 |
局部的上下文环境数据内容(函数)包含以上部分
参数 | 赋值 |
arguments | 赋值 |
自由变量的取值作用域 | 赋值 |
二 执行上下文栈
执行全局代码时,会产生一个全局上下文环境,每次调用函数时又会产生一个函数上下文环境. 当函数调用完成时,这个函数上下文环境以及其中的数据都会被销毁,再重新回到全局上下文环境. 处于活动状态的执行上下文环境只有一个,实际上,就是一个压栈和出栈的过程.
此处为图片
var a = 10; //1. 进入全局上下文环境
var fn = function(y) {
var c = 5;
console.log(y + c);
};
var bar = function(x) {
var b = 5;
fn(x + b); //3. 进入fn函数上下文环境
};
bar(10); //2. 进入bar函数上下文环境
示例说明:
- 1. 在执行代码之前,首先将创建全局上下文环境;
全局上下文环境 | |
a | undefined |
fn | undefined |
bar | undefined |
this | window |
-
- 代码执行,当代码执行到bar()方法时,全局上下文环境中的变量都在执行过程中被赋值.
全局上下文环境 | |
a | 10 |
fn | function |
bar | function |
this | window |
-
- 调用bar函数,进入函数内部,在执行函数体语句之前,会创建一个新的执行上下文环境
bar函数-执行上下文环境 | |
b | undefined |
x | 10 |
arguments | [10] |
this | window |
-
- 将这个执行上下文环境压栈,设置活动状态:
此处为图片
-
- 代码执行到fn(x + b)时,进入fn函数,在执行函数体语句之前,创建fn函数的执行上下文环境,并压栈,设置活动状态.
此处为图片
-
- fn函数执行完毕,通过fn函数产生的执行上下文环境出栈,并且被销毁(使用完成会被销毁,释放内存,正常情况下如此).
此处为图片
-
- bar函数执行完毕,通过bar函数产生的执行上下文环境出栈,并且销毁.
此处为图片
二 作用域和执行上下文环境的关系
除了全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了,而不是在函数调用时确定.
示例:
var a = 10, b = 20;
function fn(x) {
var a = 100, c = 300;
function bar(x) {
var a = 1000; d = 4000;
}
bar(100);
bar(200);
}
fn(10);
1 作用域和执行上下文环境的关系如图:
此处为图片
说明:
作用域只是一个”地盘”,一个抽象的概念,其中没有变量,要通过作用域对应的执行上下文环境来获取变量的值,在同一个作用域下不同的调用会产生不同的执行上下文环境,继而产生不同的变量的值.
2 自由变量
在A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个自由变量.
var x = 10;
function fn() {
console.log(x); //这里的x是自由变量
}
3 作用域链
-
- 先在当前的作用域查找x,如果有则获取并结束,如果没有则继续;
-
- 如果当前作用域是全局作用域,则证明x未定义了,结束,否则继续;
-
- (不是全局作用域,那就是函数作用域)将创建该函数的作用域作为当前作用域;
-
- 跳转到第一步.
示例:
var a = 10, b = 30;
function fn(x) {
var a = 100, c = 300;
function bar(x) {
var a = 1000, d = 4000;
}
bar(100);
bar(200);
}
fn(10);