作用域及作用域链

2017-04-06  本文已影响12人  路西法丶L
变量作用域

在 JavaScript 中全局变量的作用域是全局的,在代码的任何地方都是有定义的。然而函数的参数和局部变量只在函数体内有定义。另外局部变量的优先级要高于同名的全局变量,也就是说当局部变量与全局变量重名时,局部变量会覆盖全局变量。例:

var a = 1;            // 声明一个全局变量
   function num() {
      var a = 2;        // 声明一个局部变量
       return a;
   }
   console.log(num());    // 输出:2

PS:声明局部变量时一定要使用 var,否则,解释器会将该变量当做全局对象 window 的属性。

函数作用域

在 JavaScript 中使用的是函数作用域(变量在声明它们的函数体以及这个函数体嵌套的任意函数体都是有定义的)。

function num() {
    console.log(a);           //输出:undefined,而非报错,因为变量 a 在整个函数体内都是有定义的
    var a = 1;                //声明 a 在整个函数体内都有定义
    console.log(a);           //输出:1
}
num();

PS:JavaScript 的函数作用域是指在在函数内声明的所有变量在函数体内始终是可见的,也就是说在函数体内变量声明之前就已经可用了。

作用域链

在 JavaScript 中,函数也是对象,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列供 JavaScript 引擎访问的内部属性。其中一个内部属性是 [[Scope]],该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。
例如:

var x = 10
bar()
function foo() {
  console.log(x)
}
function bar(){
  var x = 30
  foo() //  输出 10
}
/* 作用域链查找过程伪代码
1. 
globalContext = {
  AO: {
    x: 10
    foo: function
    bar: function
  },
  Scope: null
}

声明 foo 时 得到下面
foo.[[scope]] = globalContext.AO
声明 bar 时 得到下面
bar.[[scope]] = globalContext.AO
在当前的执行上下文内声明的函数,这个函数的 [[scope]] 就执行当前执行上下文的 AO

2. 当调用 bar() 时, 进入 bar 的执行上下文
barContext = {
  AO: {
    x: 30
  },
  Scope: bar.[[scope]] //globalContext.AO
}
当调用 foo() 时,先从 bar 执行上下文中的 AO 里找,找不到再从 bar 的 [[scope]] 里找,找到后即调用。

3. 当调用 foo() 时,进入 foo 的执行上下文
fooContext = {
  AO: {},
  Scope: foo.[[scope]] // globalContext.AO
}
因此,输出结果是 10
*/

【注】版权归 Lucifer 所有,转载请联系作者。

上一篇 下一篇

猜你喜欢

热点阅读