1、什么是作用域execution context?
作用域又叫执行环境,或者执行上下文,执行环境定义了变量或者函数有权访问的其他数据。
2、什么是作用域链scope chain?
当代码在一个环境执行时,会创建变量对象的一个作用域链,作用域链保证执行环境有权访问的所有变量和函数的顺序。作用域链的前端是当前执行代码所在环境的变量对象
3、什么是活动对象activation object?
活动对象就是执行上下文中的变量或者函数,或者未定义的标识符。
活动对象和作用域链共同构成了执行上下文,当代码之心进入到某一个执行上下文中后,标识符解析会沿着作用域链一级一级地搜索,当然,搜索的最前端就是当前执行上下文的作用域。
举例说明:
示例1
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo() // 输出什么
}
<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<script>
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo() // 输出什么
}
/*
分析:
1、
globalcontext:{
AO: {
x:10,
foo:function(),
bar:function()
}
scope:null
}
声明bar(),得到bar的作用域链
globalcontext.AO
声明foo(),得到foo的作用域链
globalcontext.AO
2、
调用bar(),进入bar的执行上下文
barcontext:{
AO:{
x:30
}
scope:globalcontext.AO
}
3、
调用foo,进入foo的执行上下文
foocontext:{
AO:{
}
scope:globalcontext.AO
}
因为foo没有活动对象,x就只能按照作用域链去找上一级。即globalcontext.AO,x= 10.
因此输出x = 10
*/
</script>
</head>
</html>
示例2
var x = 10;
bar() // 输出什么 30
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<script>
var x = 10;
bar() // 输出什么 30
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
/*
1、
globalcontext:{
AO:{
x:10;
bar:function
}
scope:null
}
声明bar(),对应的scope为:globalcontext.AO
2、
执行bar
barcontext:{
AO:{
x:30,
foo:function
}
scope:globalcontext.AO
}
声明foo,对应的fooscope:barcontext.AO
3、
执行foo
foocontext:{
AO:{}
scope:barcontext.AO //scope:barcontext.AO == AO:{x:30,foo:function}
}
4、console.log(x)
x 在foo.AO中没有,就沿着作用域链往上搜索,foo.scope == AO:{x:30,foo:function} 得到x == 30
因此输出的是x = 30
*/
</script>
</head>
</html>
示例3
var a = 1;
function fn(){
console.log(a);
var a = 5;
console.log(a);
a++;
var a;
fn3();
fn2();
console.log(a);
function fn2(){
console.log(a);
a = 20;
}
}
function fn3(){
console.log(a)
a = 200;
}
fn();
console.log(a);
分析
<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<script>
var a = 1;
function fn(){
console.log(a);
var a = 5;
console.log(a);
a++;
var a;
fn3();
fn2();
console.log(a);
function fn2(){
console.log(a);
a = 20;
}
}
function fn3(){
console.log(a)
a = 200;
}
fn();
console.log(a);
/*
globalcontext = {
AO:{
a:1,
fn:function(),
fn3:function()
}
scope:null
}
1、初始化fn fn3
fn[scope]:globalcontext.AO
fn3[scope]:globalcontext.AO
2.执行fn
fncontext:{
AO:{
a:undefined,
fn2:function,
}
scope:globalcontext.AO
}
初始化fn2:
fn2[scope] : fncontext.AO
(1)执行console.log(a);
由于a:undefined, 所以输出 undefined
(2)然后执行a = 5;
此时fncontext.AO 中的a = 5.
(3)执行console.log(a); 此时a= 5. 所以输出:5
(4)a++ ==> a = 6,此时 fncontext.AO.a = 6
(5) 执行fn3,进入fn3的作用上下文:
fn3context:{
AO:{
null;
}
scope:globalcontext.AO
}
(5.1)执行console.log(a);
因为a不存在与fn3context.AO中,所以沿作用域链往上层搜索,
在globalcontext.AO中,a = 所以输出:1
(5.2)执行 a = 200 使得全局globalcontext.AO 中的a = 200
(6)执行fn2 ,进入fn2的作用上下文
fn2context:{
AO:null
scope:fncontext.AO
}
(6.1)执行console.log(a); 从作用域链找到fncontext.AO
得到 a = 6. 所以输出:6
(6.2)执行a = 20 fncontext.AO.a = 20
(7)执行 console.log(a); 在fncontext.AO 中得出 a = 20
所以输出:20
3.跳出fn 执行 console.log(a);
a在globalcontext.AO a = 200 所以输出:200
*/
</script>
</head>
</html>