在JavaScript中,作用域(Scope)和作用域链(Scope Chain)是理解变量如何被访问和查找的重要概念
作用域
作用域指的是变量和函数在程序中可访问的区域。JavaScript中有两种主要的作用域类型:全局作用域和局部作用域(也称为函数作用域,ES6及以后引入了块级作用域)。
- 全局作用域:在代码的最外层声明的变量或函数,它们属于全局作用域。在全局作用域中声明的变量或函数可以在整个程序中的任何地方被访问。
- 局部作用域(也称为函数作用域):在函数内部声明的变量或函数,它们只能在函数内部被访问。这有助于避免变量名冲突,并保持代码的封装性。
- 块级作用域(ES6及以后引入):使用let和const声明的变量具有块级作用域,这意味着它们只能在声明它们的代码块(如if语句、for循环等)内部被访问。
作用域有什么作用
控制着当前执行代码对变量的访问权限,说到变量,就要说下变量对象了,什么是变量对象呢?
变量对象
变量对象是javaScript执行上下文(Execution Context)中的一个内部对象,它负责存储在该执行上下文中声明的变量、函数声明以及函数的参数。不同类型的上下文(如全局上下文、函数上下文)会有不同的变量对象。变量对象分为全局变量对象和局部变量对象。全局简称为 Variable Object VO 局部变量对象由于函数执行才被激活 称为 Active Object AO
var value = 1;
function foo() {console.log(value);
}
function bar() {var value = 2;foo();
}
bar(); // 1
作用域链
概念:作用域链是JavaScript在查找变量时的一个过程或机制。当JavaScript引擎需要查找一个变量时,它会首先在当前作用域中查找,如果找不到,就会向上在父作用域中查找,这个过程会一直持续到全局作用域。如果在全局作用域中仍然找不到该变量,那么JavaScript会抛出一个ReferenceError错误。
原理:在js中, 函数存在一个隐式属性 [[scopes]], 这个属性用来保存当前函数的执行上下文环境, 由于在数据结构上是链式的, 因此也被称作是作用域链, 我们可以把它理解为一个数组
可以理解为是一系列的AO对象所组成的一个链式结构
function a(){}
console.dir(a) // 打印结构
当函数被调用后
function a(){console.dir(a)
}
a()
a函数的执行上下文如下
因此我们可以得出一个结论: [[scopes]] 属性在函数声明时产生, 在函数调用时更新
即: 在函数被调用时, 将该函数的AO对象压入到[[scopes]]中
作用域链的作用
作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的
最直观的表现就是:
- 函数内部可以访问到函数外部声明的变量
var a = 100
function fn(){console.log(a)
}
fn() // 100
- 函数外部访问不到函数内部的变量
function fn() {var a = 100
}
fn()
console.log(a) // a is not defined