# 作用域与动态作用域

# 1、作用域

作用域就是程序源代码中定义变量的区域。作用域规定了执行代码对变量的访问权限。js采用词法作用域(lexical scoping)也就是静态作用域。

# 2、静态作用域与动态作用域

静态作用域:函数的作用域在函数定义的时候就决定了。 动态作用域:函数的作用域是在函数调用的时候才决定的。

const value = 1;
function foo(){
	console.log(value)
}
function bar(){
	const value = 2;
	foo();
}

静态作用域下,foo执行时,会先在该函数内查找变量,没有就直接去上一层找,所以找到了value = 1; 动态作用域下,foo执行时,在该函数内没找到,则去调用该函数的那一层找,所以找到了value = 2;

# 3、静态作用域实例

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope();
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()();

两段代码最终打印的都是local scope。 JavaScript 函数的执行用到了作用域链,这个作用域链是在函数定义的时候创建的。嵌套的函数 f() 定义在这个作用域链里,其中的变量 scope 一定是局部变量,不管何时何地执行函数 f(),这种绑定在执行 f() 时依然有效。

# 4、执行上下文栈

js引擎并非一行一行分析和执行程序,而是一段一段分析执行。当执行一段代码的时候,会进行一个准备工作。比如第一个例子中的变量提升,和第二个例子中的函数提升。 更详细的说,这个准备工作就是创建一个执行上下文栈,来管理执行上下文,通过压入执行上下文栈,执行完成后推出来执行代码。

var foo = function () {

    console.log('foo1');

}

foo();  // foo1

var foo = function () {

    console.log('foo2');

}

foo(); // foo2
function foo() {

    console.log('foo1');

}

foo();  // foo2

function foo() {

    console.log('foo2');

}

foo(); // foo2

每个执行上下文,都有三个重要属性:

  • 变量对象
  • 作用域链
  • this

# 5、变量对象

变量对象是执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明。