JavaScript 之 执行上下文
2019-11-05 本文已影响0人
_一九九一_
先介绍变量的存放
栈数据结构 :
- 后进先出的数据结构
- 基本类型:Undefined、Null、Boolean、Number 、String和Symbol
- 按值访问, 栈比堆的运算速度快
堆 :
- 引用类型:因为大小不固定,所以不能保存到栈内存中,但内存地址大小的固定的,在栈内存中存放的只是该对象的访问地址。
- 当查询引用类型的变量时, 先从栈中读取内存地址, 然后再通过地址找到堆中的值。对于这种,我们把它叫做按引用访问。
队列
- 先进先出的数据结构 事件循环的基础结构
栈堆练习题
a、b都是基本类型,它们的值是存储在栈中的,a、b分别有各自独立的栈空间,修改不影响
var a = 20;
var b = a;
b = 30;
// 这时a的值是多少? 20
a、b都是引用类型,栈内存中存放地址指向堆内存中的对象,引用类型的复制会为新的变量自动分配一个新的值保存在变量对象中,但只是引用类型的一个地址指针而已,实际指向的是同一个对象,所以修改b.name的值后,相应的a.name也就发生了改变。
var a = { name: '前端' }
var b = a;
b.name = '开发';
// 这时a.name的值是多少 '开发'
null是基本类型,a = null之后只是把a存储在栈内存中地址改变成了基本类型null,并不会影响堆内存中的对象,所以b的值不受影响
var a = { name: '前端开发' }
var b = a;
a = null;
// 这时b的值是多少 '前端开发'
执行上下文
-
如何管理创建的那么多执行上下文: JavaScript 引擎创建了执行上下文栈来管理执行上下文,
来管理出栈入栈的状态, -
全局执行上下文:只有一个,浏览器中的全局对象就是 window 对象,this 指向这个全局对象。
-
函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文。
-
Eval 函数执行上下文: 指的是运行在 eval 函数中的代码,很少用而且不建议使用。
模拟执行上下文栈
- 程序结束之前, ECStack 最底部永远有个 globalContext
ECStack = [];
ECStack = [
globalContext
];
function fun3() {
console.log('fun3')
}
function fun2() {
fun3();
}
function fun1() {
fun2();
}
fun1();
// 伪代码
// fun1()
ECStack.push(<fun1> functionContext);
// fun1中竟然调用了fun2,还要创建fun2的执行上下文
ECStack.push(<fun2> functionContext);
// fun2还调用了fun3
ECStack.push(<fun3> functionContext);
// fun3执行完毕
ECStack.pop();
// fun2执行完毕
ECStack.pop();
// fun1执行完毕
ECStack.pop();
// javascript接着执行下面的代码,但是ECStack底层永远有个globalContext
变量提升
foo; // undefined
var foo = function () {
console.log('foo1');
}
foo(); // foo1,foo赋值
var foo = function () {
console.log('foo2');
}
foo(); // foo2,foo重新赋值
函数提升
foo(); // foo2
function foo() {
console.log('foo1');
}
foo(); // foo2
function foo() {
console.log('foo2');
}
foo(); // foo2
声明优先级,函数 > 变量
foo(); // foo2
var foo = function() {
console.log('foo1');
}
foo(); // foo1,foo重新赋值
function foo() {
console.log('foo2');
}
foo(); // foo1