JavaScript作用域和作用域链

JavaScript作用域和作用域链

1.作用域

​ 在我的上一篇文章中,说到作用域的概念。那什么是作用域?很多解释:是代码中变量的可用范围(可见性、可访问性);是可访问变量,对象,函数的集合。在《你不知道的JavaScript上卷》一书中提到编程语言需要一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量。这套规则称为作用域。

​ 那作用域到底是一套规则还是可访问变量、对象、函数的集合呢?(在我看来集合和规则是不一样的,不知各位的看法如何)集合更像是实体,有具体的组成。规则更像是概念的和抽象的行为规范。

​ 《JavaScript高级程序设计》4.2章节中没有直接对作用域下定义,但是提到了作用域链:当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。第四版经过了描述的调整,大意仍然是会创建变量对象的作用域链,决定了各级上下文中代码在访问变量和函数时的顺序。作用域链顾名思义是由一个个作用域组成(事实确实如此)。从以上来看,我更倾向于:作用域是一套规则,他决定了代码中变量、对象、函数的可访问/见性。即作用域是规则,他决定可访问性,集合是应用它产生的结果。

​ 那这一套规则是怎么形成的?知道了它的定义和用处,总得知道它来自何处。作用域主要有两种:词法作用域、动态作用。JavaScript采用的是词法作用域(动态作用域本文不做介绍)。词法作用域就是定义在词法阶段的作用域,是由你在书写代码时将变量和块作用域写在哪里决定的

​ 作用域可分为:全局作用域、函数作用域、块作用域

function foo(a) {
    var b = 2
    if(b === 2) {
        let c = 3
    }
}
foo(1)

​ 以上的代码其实就包含了三种作用域,这就是你在书写这些代码时就决定的。全局作用域,集合里面有函数foo();函数作用域里面有变量a,b;块作用域变量c。

​ 怎样的变量和函数才拥有全局作用域呢?

1.在最外层定义的变量和函数拥有全局作用域

2.未定义直接赋值的变量拥有全局作用域

3.所有window对象的属性拥有全局作用域

​ foo()函数拥有全局作用域就属于第一种情况,它书写在最外层,没有被其他函数或者块包含。

function foo() {
    b = 2
}
foo()
console.log(b) // 2

​ 我们在函数外部打印变量b,是可以访问的,可见它并没有在函数foo()所创建的函数作用域之内。这是因为变量b是在函数中直接赋值的,并没有定义,转变为在全局作用域之内(函数只是一个实例,只要是直接赋值未定义都适用)。

​ 函数作用域和块作用,经过我上篇文章的介绍想必已经很清楚了。即:

1.函数作用域,是指声明在函数内部的变量,只有固定的代码片段才可以访问

2.块级作用域可以通过let和const声明,只有在指定的块作用域才能被访问

2.作用域链

​ 作用域链在上文其实已经有介绍了:上下文中的代码在执行的时候,会创建变量对象的一个作用域链。这个作用域决定了各级上下文中的代码在访问变量和函数时的顺序。作用域只是决定了变量的可见性,并没有决定查找顺序的功能,既然有顺序的功能,则一定要有某种结构才对。

function foo(a) {
    var b = 2
    if(b === 2) {
        let c = 3
    }
}
foo(1)

​ 观察上述代码或许你已经发现了,全局作用域、函数foo()作用域、if块作用域其实并不是毫无关联的。全局包含函数foo(),函数foo()作用域又包含着if块作用域,它们呈逐级包含的关系。正是这种位置关系形成的链条,才能决定查找变量的顺序。

那是按照怎么样的顺序查找的?

function foo(a) {
    var b = 2
    let c = 4
    if(b === 2) {
        let c = 3
        console.log(a, b, c) // 1 2 3
        console.log(d) // ReferenceError: d is not defined at foo
    }
}
foo(1)

上述代码在执行if块的console.log(a, b, c)语句时。if块作用域中只存在变量c,包含它的foo()函数作用域有变量a、b、c,其中变量c和if块作用域中变量c同名。变量c打印出来3,并不是4。变量a、b也成功查找打印出来1、2,变量d则抛出ReferenceError错误。可见访问变量和函数时的顺序是:首先在当前作用域开始查找,如果引擎没有找到对应的标识符(变量、函数),则会逐级往上级作用域查找,直到找到标识符为止,如果在全局作用域都没有找到通常就会报错

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值