本博客 hjy-xh,转载请申明出处
作用域的定义
当前的执行上下文。值和表达式在其中 “可见” 或可被访问到的上下文。如果一个变量或者其他表达式不 “在当前的作用域中”,那么它就是不可用的。作用域也可以根据代码层次分层,以便子作用域可以访问父作用域,通常是指沿着链式的作用域链查找,而不能从父作用域引用子作用域中的变量和引用。
从上面的定义出发,可以简单概括为:作用域决定了变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期
。
作用域分类
作用域分为两种
- 全局作用域
- 函数作用域
全局作用域特性
- 全局作用域在当 JavaScript 开始要解释执行代码的时候被创建,整个程序结束的时候被销毁
- 全局对象在不同的宿主环境下是不同的,在浏览器环境下,全局对象即为
window
,代表一个浏览器窗口,由浏览器创建,可以直接调用 - 全局作用域中声明的变量和函数会作为
window
对象的属性和方法保存,作用域为全局,在任何地方都能访问到
局部作用域特性
- 调用函数时,函数作用域被创建,函数执行完毕,其作用域被销毁
- 每调用一次函数就会创建一个新的函数作用域,它们之间是相互独立的
- 在函数作用域中可以访问到全局作用域的变量,在函数外无法直接访问到函数作用域内的变量
- 在函数作用域中访问变量,会现在自身作用域中查找,如果没有找到,则回到函数的上一级作用域中查找,一直到全局作用域
作用域链(Scope Chain)
当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。
总结:Javascript 引擎会沿着作用域链(Scope Chain) 寻找需要的变量。
作用域的深层次理解
执行上下文
JavaScript 引擎创建了执行上下文栈(Execution context stack,ECS)来管理执行上下文
- 在执行函数前,会创建一个执行上下文的内部对象 AO(作用域)
- 这个内部对象时预编译时被创建出来的,在函数被调用时,会先进行预编译
- 在全局代码执行前会创建一个执行上下文的对象 GO
预编译
函数作用域预编译
- 创建 AO 对象
- 找形参和变量声明,将函数内的变量和形参名作为 AO 对象的属性名,值为 undefined
- 将实参和形参相统一
- 在函数体中找函数声明,值赋予函数体
全局作用域预编译
- 创建 GO 对象
- 找变量声明,将变量名作为 GO 对象的属性名,值为 undefined
- 找函数声明,值值赋予函数体