原生JS笔记01:执行环境与作用域链

概念

  1. 执行环境(execution context):是JavaScript中一个非常重要的概念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。

  2. 执行环境的变量对象:每个执行环境都有一个对应的变量对象,它用于存储环境中定义的所有变量和函数。我们在代码中无法直接访问它,但解析器在后台会实际使用它。

  3. 作用域链(scope chain):当函数被执行时,它的执行环境会被推入一个环境栈中。在函数被执行完毕后,会从栈中弹出,将控制权交给栈顶的执行环境,栈底是全局执行环境。当我们查询标识符的作用时,采用就近原则,从栈顶向栈底查找,这就是作用域链。

执行环境

  1. 全局执行环境
    全局执行环境根据宿主的不同,会有变化。
    众所周知,JavaScript实际上是ECMAScript以Web浏览器为宿主后的称谓。一个简单的公式如下:
    JavaScript = ECMAScript + BOM + DOM
    所以,JavaScript的所有全局变量和函数,都是作为window对象的属性创建的。
function my_global_func(){
console.log(123)
}
var test_var = 'hello'

console.log(window.test_var) // hello
console.log(window.my_global_func) // ƒ (){console.log(123)}
  1. 局部执行环境
    每个函数都有自己的局部执行环境,生成一个“变量对象”,函数内定义的所有变量和函数,都会作为“变量对象”的属性存在。
var color = 'blue'
function changeColor(){
    color = 'red'
}
changeColor()

如上面这段代码所示,存在一个全局执行环境和一个局部执行环境,该局部执行环境由函数“changeColor”生成。
在此段代码片段中,函数“changeColor”的局部执行环境中,并没有定义任何变量,因此该局部执行环境中只有一个默认的变量: arguments。

  1. arguments
    在任何函数中,都存在一个默认的无需定义的变量:arguments,它以数组的形式存储函数的入参。
    也可以认为,它是函数执行环境中,“变量对象”的默认属性,值得注意的是,全局执行环境没有arguments属性。
var test = function(){
console.log(arguments)
}
test('1','2') //['1','2']

console.log(arguments) // 报错

arguments除了包含函数入参,拥有数组的方法以外,还拥有一个callee方法,这个方法的具体用法,后面再讲。

作用域

作用域:一个函数/变量可以被使用的作用范围,被称为作用域。
在JAVA、C、C++ 等开发语言当中,变量/函数 的作用域以块为单位。但在JavaScript这门语言当中,却不是以块为单位进行作用域的判断的。

if(true){
    var color = 'blue'
}
console.log(color) // blue

在存在块级作用域的语言中,以上代码会报错,但JavaScript却能够打印出在if块中定义的变量的值。原因在于JavaScript中var关键字定义的变量存在“变量”提升这个过程,在编译的过程中,实际执行过程如下:

var color = undefined
if(true){
     color = 'blue'
}
console.log(color) // blue

而变量提升的本质,是提前给执行环境中的“变量对象”设置属性值,而局部执行环境已函数为单位,因此变量提升的过程也只到函数这一层。
那么,在一个函数内,是否可以访问其执行环境以外的变量呢?
答案当然是肯定的。

var color = 'blue'
function test(){
  console.log(color)
}
test() // blue

通过上面这个简单的例子,我们可以发现,在函数的局部执行环境中,可以访问全局执行环境中的变量。

var color = 'blue'
function test(){
    var color02 = 'red'
    var test02 = function(){
        console.log(color)
        console.log(color02)
    }
    test02()
}
test() // blue  red

通过上面这个例子,我们可以发现,在函数的局部执行环境中,不仅可以访问全局执行环境的变量,还可以访问上一层函数中定义的变量。
实际上:在一个函数被执行时,它被推入一个环境栈,最上层永远是执行中的函数的执行环境,其次为该函数的上一层函数的执行环境,以此类推,底层为全局执行环境。
当编译器寻找标识符时,会从栈顶向栈底依次搜寻,一旦找到符合条件的标识符便结束此次搜寻,如果编译器未能找到该标识符,便会报错。

    原文作者:张仕春
    原文地址: https://www.jianshu.com/p/0922461733eb
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞