JavaScript 之执行环境及作用域

87 阅读3分钟

执行环境

执行环境是JavaScript中最重要的一个概念。执行环境定义了变量和函数访问其它数据的规范行为。
全局执行环境是最外围的一个执行环境。在Web 浏览器中,全局执行环境是window对象,所有的全局变量和函数都是作为window对象的属性和方法创建的。
每个函数都有自己的执行环境,当函数执行时,函数的执行环境就会被推入一个环境栈中。而当函数执行后,环境会被栈弹出。

作用域

当代码在环境中执行时,会创建变量对象的一个作用域链。 作用域链的作用是对执行环境有权访问的变量和函数进行有序访问。
JavaScript需要查找一个变量时,她会从链中第一个对象开始查找,如果对象中找不到会继续查找链上的下一个对象,以此类推。如果作用域链上没有找到就会抛出一个引用错误(ReferenceError)异常

var color = 'blue'

function changeColor(){
  var anotherColor = 'red'

  function swapColors(){
    var tempColor = anotherColor
    anotherColor = color
    color = tempColor
    console.log('tempColor',tempColor);
  }

  swapColors()

  console.log('anotherColor',anotherColor);
}

changeColor()

console.log('color',color);

// =>
tempColor red
anotherColor blue
color red

上面代码包含三个执行环境:全局环境,changeColor()的局部环境和swapColors()的局部环境。
全局环境可以访问变量color和函数changeColor(). changeColor()的局部环境可以访问变量anotherColor和函数swapColors(),同时还可以访问全局环境的变量color
swapColors()可以访问tempColor,以及changeColor()和全局环境中的变量。

image.png

内部环境可以通过作用域链访问所有的外部环境。但任何环境都不能通过向下搜索作用域链而进入执行环境。

函数作用域

javascript中没有块级作用域,使用的是函数作用域。函数作用域是指在函数内声明的所有变量在函数体内始终可见。

function test(o){
  var i = 0                           // 可在函数内访问
  if(typeof o === "object" ){
    var j = o                         // j在函数内定义了,可以在函数内任何地方访问
    for (var k = 0; k < 10; k++) {
      console.log(k);                 // 输出 0~9
    }
    console.log(k);                   // k已经定义,输出10
  }
  console.log(j);                     // j可以访问但可能没有初始化 值可能为o或者undefined
}

在这个例子中,由for循环创建的变量k即使在for循环执行完后依旧存在循环外部的环境。

声明提前

var scope  = "global"

function f(){
  console.log(scope);     // 输出 undefined
  var scope = "local"     // 变量初始化赋值,但变量本身在函数体内始终定义的
  console.log(scope);     // 输出 local
}

等同于下面例子

function f(){
  var scope               // 在函数顶部声明了局部变量
  console.log(scope);     // 变量声明未初始化赋值,其值是 undefined
  scope = "local"         // 初始化赋值
  console.log(scope);     // 输出 local
}

将函数体内的变量声明提前至函数体顶部,变量初始化留在原来的位置

变量作用域

function add(x,y){
  sum = x + y
  return sum
}
var result = add(1,2)
console.log(result); // 3

这个例子中的变量sum在初始化时未使用var 关键字。于是变量sum被添加到全局环境,称为了全局变量,所以在函数外部可以访问。