作用域与执行上下文

106 阅读2分钟

作用域

  • js 采用的是静态作用域,所以函数的作用域在函数定义时就确定了,并且不会改变。
var value = 1;
function foo() {
    console.log(value);
}
function bar() {
    var value = 2;
    foo();
}
bar();
// 打印 1
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope();
// 打印 local scope
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()();
// 打印 local scope

执行上下文

  • 执行上下文在运行时确定,随时可能改变。

  • 执行上下文后才执行代码。

  • 在进入执行上下文时,首先会处理函数声明,其次会处理变量声明,如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。

全局上下文

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

  • 全局上下文中的变量对象就是全局对象(如window(不同环境不同))

// 执行上下文后的变量对象
// window = {
//   ...window,
//   a: undefined
// }

var a = 1
b = 2 // 到这边变量对象添加 b: 2

console.log(window.a) // 打印1
console.log(window.b) // 打印2

// 执行上下文后的变量对象
// window = {
//   ...window,
//   a: function () {}
// }

  console.log(a); // 打印函数
  function a() {}
  var a = 1

函数上下文

  • 在函数上下文中,用活动对象(activation object, AO)来表示变量对象。

  • 活动对象是在进入函数上下文时刻被创建的,它通过函数的 arguments 属性初始化。arguments 属性值是 Arguments 对象。

// 执行函数上下文后的变量对象
// VO = {
//   arguments: {
//     0: 1,
//     length: 1
//   },
//   a: 1,
//   b: undefined
// }

  function a(a) {
    console.log(a); // 打印1
    var a = 2
    var b = 3
  }
  a(1)
// 执行函数上下文后的变量对象
// VO = {
//   arguments: {
//     length: 0
//   },
// }

function foo() {
    console.log(a); // 由变量对象拿不到,在这直接报错 a is not defined
    a = 1;
}
foo();