执行上下文对象:
在浏览器执行javascript代码之前,浏览器会做一些准备工作(从准备工作这一操作开始,直到对应的这一作用域的所有代码被执行完,这样的一个过程就叫做执行上下文;执行上下文可以被看成一个对象,这个对象
就是用来管理其对应作用域中的各个数据,这些数据就是对象中的属性).
一. 全局作用域中的一些准备工作
1. 找到标记的全局变量,并为其赋值为undefined;
2. 给this赋值为window对象
3. 函数声明,并给函数赋值为整个函数块
二. 函数作用域中的一些准备工作
1. 找到标记的局部变量,并为其赋值为undefined;
2. 给this赋值为window对象;
3. 函数声明,并给函数赋值为整个函数块;
4. 给参数赋值; (管理参数的数组对象)arguments赋值;
5. 确定自由变量的取值作用域,并给自由变量赋值;
由上面几点看出:
1. 函数被定义的时候,就确定了函数体内部变量的作用域;
2. 函数每被调用一次,就会产生一个新的执行上下文对象,因为不同的调用会有不同的参数;
三. 全局执行上下文对象的数据内容:
全局变量如:var a=10 或 函数表达式如:var fn={} : 声明(默认值为undefined)
函数声明如:function fun() {} : 给这个函数赋值为整个函数块
this : 赋值为window对象
四. 局部(函数)执行上下文对象的数据内容:
全局变量如:var a=10 或 函数表达式如:var fn={} : 声明(默认值为undefined)
函数声明如:function fun() {} : 给这个函数赋值为整个函数块
this : 赋值为window对象
参数 : 赋值(传进来的值)
arguments : 赋值(参数的值,未传实参时,赋空值)
自由变量的取值作用域 : 找到自由变量的作用域,并赋值
五. 执行上下文栈
执行全局代码时,会产生一个全局上下文环境(压栈),每调用全局中的一个函数时,又会产生一个函数上下文环境,当函数调用完成时,这个函数上下文环境被销毁(出栈),在重新回到全局上下文环境.处于活动状态的上下文环境始终只有一个,这就是压栈和出栈的过程.
例: var a = 10; //进入全局上下文环境
var fn = function(y){
var c = 5;
console.log(y + c);
};
var bar = function(x){
var b = 5;
fn(x + b); //进入fn函数上下文环境
};
bar(10); //进入bar函数上下文环境
解析:
1. 在执行代码之前,首先创建全局上下文环境,此时各个变量的状态为:
全局变量a undefined
全局变量fn undefined
全局变量bar undefined
this window对象
2. 创建全局上下文环境后,开始从上到下依次执行,当读到bar()这句时,前面的全局上下文环境中的变量都被赋值,此时的状态为:
全局变量a 10
全局变量fn function
全局变量bar function
this window对象
3. 调用bar函数时(即读bar(10)这条语句),进入函数内部,在执行函数体内部语句之前,创建一个新的该函数作用域的上下文环境,把这个上下文环境压栈,设置为活动状体,此时的状态为:(bar函数的上下文环境)
局部变量b undefined
x 10
arguments [10]
this window对象
4. 创建bar的上下文环境后,开始从上到下依次执行bar内的代码,当读到fn(x+b)时,前面的bar的上下文环境中的变量都被赋值,此时的状态为:
局部变量b 5
x 10
arguments [10]
this window对象
5. 调用fn()函数时(即读fn(x + b)这条语句),进入函数内部,在执行函数体内部语句之前,创建一个新的该函数作用域的上下文环境,把这个上下文环境压栈,设置为活动状体,此时的状态为:(fn函数的上下文环境)
局部变量c undefined
y 15(x+b)
arguments [15]
this window对象
6. 当fn函数的上下文环境执行完后,fn的上下文环境被销毁,删除这个上下文环境的所有数据,也就是出栈;此时重新回到bar函数的上下文环境;
7. 当bar函数的上下文环境执行完后,bar的上下文环境被销毁,删除这个上下文环境的所有数据,也就是出栈;此时重新回到全局作用域的上下文环境,直到所有代码执行完毕.
六. 作用域和执行上下文的关系
1. 在代码中,除了全局作用域外,每个函数都会创建自己的作用域;
2. 作用域是在函数被定义的时候就确定的,而不是在调用时被确定的;
3. 作用域只是一个抽象的概念,其中并没有变量,需要通过作用域对应的上下文环境来获取变量的值;
4. 在同一个作用域下,每次的调用,都会产生不同的上下文环境,当然就会产生不同的变量的值(即使值一样,所在的内存区域却不一样)
例: (这个例子没看出哪里体现了上面的第2点)
var a = 10, b = 20;
function fn(x){
var a = 100, c = 300;
function bar(x){
var a = 1000, d = 4000;
console.log(a + " " + d);
}
bar(100);
bar(200);
}
fn(10);
七. 自由变量
1. 概念: 在作用域A中,使用了变量X,但并没有在A作用域中声明(即在其他作用域声明的变量X),对于作用域A来说,X就是一 个自由变量.
例: var X = 10;
function fn(){
console.log(X); //这里的X就是一个自由变量
}
八. 作用域链(这里用变量X举例来说明)
1. 先在当前所在的作用域查找变量X,如果有,则获取,如果没有,则向当前作用域的上一级继续查找,如果找到,则获取那一级的值;如果还是没有,一直查找到全局作用域;
2. 如果继续查找到当前的作用域为全局作用域,却还没有找到时,则表示变量X为定义,结束;
3. 不是全局作用域,那就是函数作用域.