JavaScript作用域汇总

186 阅读4分钟

这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。

  • 作用域
  • 作用域链
  • 词法作用域(静态作用域)
  • 动态作用域
  • 全局作用域
  • 局部作用域
  • 块级作用域

作用域

想象成一块区域,这块区域中,定义了各种变量对象等,这些变量的访问读取只能在这个区域内,这个区域外部的是没权限访问的!

var bee = '我是全局的'
function fn(){
    var baa = '我在函数里面呢'
    console.log(bee)
}
fn()// 我是全局的
console.log(baa);//Uncaught ReferenceError: baa is not defined

上面代码中,打印baa时会报错,因为baa是定义在函数fn局部作用域里面的,外部是没有的。

作用域链

从上面代码可以发下,在函数fn中打印外部定义的变量 bee 是没有问题的,也就是说局部作用域内是可以访问到外部作用域声明的变量的。

当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途,是 保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所 在环境的变量对象。

作用域链相当于内部作用域与外部作用域沟通的桥梁,当前执行上下文(也就是执行环境,咱也不知道为啥这么搞多种叫法,有知道的同志可以悄摸儿告诉我😄)位于作用域链的最顶端
当要读取一个变量时,从作用域链顶端开始查找,如果找不到就继续向外层查找,最外层也就是全局环境了,如果还是找不到的话,就会抛出错误了。

var dda = '我是全局'
function fn(){
    var dda = '我是fn'
    console.log(dda)
}
fn(); // 我是fn

上面代码中,打印结果是定义在fn中的值,当fn函数执行时,会创建对应的变量对象加到作用域链前端,搜索标识符从沿着作用域链从前端开始逐级搜索,找到搜索就结束了。

修改一下代码:

var dda = '我是全局'
function fn(){
    var dda = '我是fn'
    function fn2(){
      console.dir(fn2)

    }
    fn2()
    console.dir(fn)
}
fn()

以上代码会输出什么呢?

image.png 函数有一个内部属性[[Scopes]], 函数创建时,所有的父变量对象都存在这里,在当前函数调用时,再把其对应的变量对象也加到作用域链前端。

image.png

image.png

词法作用域

首先,语言分为静态作用域和动态作用域两大类
在JavaScript中呢,静态作用域就是词法作用域(lexical scoping),词法作用域又分成函数作用域和块级作用域。 词法作用域的特点就是:在定义的时候,作用域就已经确定了。 来看一个🌰

var value = 1;

function foo() {
    console.log(value);
}

function bar() {
    var value = 2;
    foo();
}

bar(); // 1

上面的代码,输出结果为1,有问题吗?没有问题。输出1正好验证了我们前面说的。
函数在创建的时候,其作用域就已经确定了。
上面foo函数是在全局定义的,刚刚的作用域链中提到的[[Scopes]],在函数创建时,它外部的变量对象就已经被加入其中了,foo被定义在全局中,那么在bar函数作用域中再调用,它除了自身创建的变量对象外,外部只有全局对象。

动态作用域

动态作用域是运行时才决定的。

词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用

函数内部的this,就是谁调用就指向谁。

var name = 'www'
function fn(){
    console.log(this.name)
}
var obj = {
    name: 'oob',
    func: fn
}
fn(); //www
obj.func(); //oob

函数作用域

在es6之前真正能划分作用域的就是函数的大括号{},除了全局作用域(常说的window),就是函数作用域了。

每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。 而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。

块级作用域

什么是块级作用域?
简单的说,{} 这个花括号里面的作用域就是块级作用域。
这是es6新增的一个概念;
es6中提供了let 与 count 关键字,它们声明的范围就是块级作用域

膜拜大佬:juejin.cn/post/705308…