执行上下文
执行上下文决定了变量和函数可以访问哪些数据。
一个执行上下文就对应一个仅后台可访问的变量对象,其中保存有该上下文的局部变量、参数和函数声明。
最外层的上下文称为全局上下文。宿主环境不同,全局上下文的关联对象就不同。在浏览器中,全局上下文就是window
对象。
注意
window
后没有s
。
除了 window 对象自带的属性外,使用var定义的全局变量和函数都会成为其属性。
var a1=1;
function func(){var a2=2;
}
console.log(a1); //输出1
console.log(typeof a2 === "undefined"); //输出true
console.log(window.a1); //输出1
window.a1
也可以写成window['a1']
。
一般的上下文在其代码执行完后就销毁,而全局上下文是在程序退出时才被销毁。
执行上下文会按照函数的调用顺序形成一个堆栈,称为执行上下文栈
。
当前执行上下文位于执行上下文栈的顶端,当它执行完后会被弹出,程序的控制权就交给之前的上下文。
我们用到的、见到的this
指针指向的就是这个当前执行上下文,其值取决于函数的调用方式。
作用域链
作用域链(scope chain)决定了变量和函数的访问权限和顺序,这个链的最前端是当前执行上下文的变量对象。
作用域链的先后顺序就是内外顺序,内部执行上下文包含了外部执行上下文。换句话说,内部执行上下文可以访问外部执行上下文。
我们访问变量和函数的顺序就是从作用域链的前面往后面找。
看个例子:
const a4=4;
var a5=5;
const func1 = function (a3) {const a2=2;function func2() {const a1=1;return function func3(){console.log(a1+a2+a3+a4+a5);}};return func2();
};
const result=func1(3);
result();
[[Scopes]]
记录的是变量的父作用域链,可以看到result并没有func3的上下文。
有两个影响作用域链的行为:with和try/catch的catch块。
使用with将指定对象的作用域推入上下文栈:
let person={name:'Carl',age:22
}
with(person){console.log(name+"'s age is "+age);
}
try/catch语句的catch块是一个单独的上下文,捕获的错误信息被添加到catch块的变量对象上,于是只能在catch块才能访问该错误。