js 执行上下文,作用域,变量内存管理
JS中变量的定义在内存中包括三个部分:
* 变量标示 (变量标示存储在内存的栈区)
* 变量值 (比如上面中的Str的值souvenir或者是obj1对象的指向堆区地址,这个值也是存储在栈区)
* 对象 (对象存储在堆区)
也就是说,对于基本数据类型来说,只使用了内存的栈区。
执行上下文堆栈
三种作用域
全局作用域、函数作用域、eval作用域(不常用,不做介绍)。
JavaScript中的运行环境大概包括三种情况。
- 全局环境:JavaScript代码运行起来会首先进入该环境
- 函数环境:当函数被调用执行时,会进入当前函数中执行代码
- eval
当javascript代码文件被浏览器载入后,首先进行上下文环境的准备工作。会将全局的执行上下文压入执行上下文栈的底部。
当在全局上下文中调用执行一个函数时,程序流就进入该被调用函数内,此时引擎就会为该函数创建一个新的执行上下文,并且将其压入到执行上下文栈。栈顶永远都是当前正在执行的上下文,执行完毕后该上下文就会从栈顶被弹出,直到回到全局的上下文。全局上下文在浏览器窗口关闭后出栈。
注意:函数中,遇到return能直接终止可执行代码的执行,因此会直接将当前上下文弹出栈。
函数作用域中this的是在JS运行时才能确定,而全局作用域中的this在准备上下文环境的时候就确定了(window)。
执行上下文的建立过程
- 建立阶段(发生在当调用一个函数时,但是在执行函数体内的具体代码以前) ○ 建立变量,函数,arguments对象,参数 ○ 建立作用域链 ○ 确定this的值
- 代码执行阶段: ○ 变量赋值,函数引用,执行其它代码
建立阶段:
- 建立variableObject对象: i. 为函数的参数和arguments对象赋值。建立arguments对象,检查当前上下文中的参数,建立该对象下的属性以及属性值 ii. 检查当前函数声明和变量。将函数名和变量名作为variableObject的一个属性 存入,属性值都设为undefined。 为函数声明直接赋值字符串
- 初始化作用域链 ○ 确定上下文中this的指向对象
执行阶段:
○ 执行函数体中的代码,一行一行地运行代码,给variableObject中的变量属性赋值。
通俗的讲,执行上下文准备工作就是在执行代码前,把将要用到的所有的变量都事先拿出来,有的直接赋值了,有的先用undefined占个空。
//将全局变量的值设为undefined
console.log(a); //undefined
var a = 1;
//将window对象赋给this
console.log(this);
//将函数表达式的值设为undefined
console.log(fn1);//undefined
var fn1 = function(){
//……
}
//为函数声明直接赋值
console.log(fn2); //输出函数的代码
function fn2(){
//……
}
//函数作用域
function fn3(b,c){
//确定自由变量的作用域
console.log(a);
//为局部变量赋上undefined
console.log(x);//undefined
var x = 123;
//为函数的参数赋值
console.log(b,c); //2,3
//为arguments赋值
console.log(arguments); //[2,3]
}
fn3(2,3);