词法作用域、块级作用域、作用域链、静态作用域、动态作用域

230 阅读3分钟

作用域

作用域是根据名称来查找变量的一套规则,可以吧作用域同属理解为一个封闭的空间,这个空间是封闭的,不会对外部产生影响,外部空间不能访问内部空间,但是内部空间可以访问将其包裹在内的外部空间。

说白了就是一门语言如果声明的变量都放在全局,程序规模小还行,如果规模一大肯定就不行了。所以就会采用各种方案来确定函数的作用域

3674815208f543c7b875d782e7d4e803_tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.awebp

静态作用域与动态作用域

静态作用域与词法作用域

其实就是指的词法作用域,所谓静态作用域,也就是说在程序编译期通过对源代码的词法分析就可以确定某个标识符属于哪个作用域、作用域嵌套关系(作用域链),在书写源代码时这些关系就已经确立了。

词法分析是编译中不可或缺的一环。

6e23e97b206f4f91b3457997b48c87da_tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.awebp

// 静态作用域: 
var a = 10; 
function fn() { 
   var b = 1; 
   console.log(a + b); 
} 
fn(); // 11
动态作用域

动态作用域是在运行时确定的,词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用,其作用域链是基于运行时的调用栈的。

js语言中的变现为this 也就是上下文环境。

function say() { 
   debugger 
   console.log('我的家乡:' + this.name) 
} 
var china = { 
   name: '中国',
   say,
   beijing :{ 
      name: '北京', 
      say 
   } 
} 
setInterval(() => Math.random() > 0.5 ? china.say() : china.beijing.say() , 1000)

因为this是指向的是函数运行时所在的环境,也就是说只有到了执行时才能确定。

函数作用域与块级作用域

对于JS这种函数式语言,函数是一等公民,甚至有人想过用函数解决所有问题。

  • 函数作用域:指在函数内声明的所有变量在函数体内始终是可见的,可以在整个函数的范围内使用及复用。
var a = 'a'
function f1() {
    var b = 'b'
    function f2() {
        var c = 'c'
        function f3() {
          if(true) {
          	var d = 'd'
        	}
          console.log(a, b, c, d)
          debugger
        }
      	f3()
    }
  	f2()
}
f1()

作用域链

ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链

微信图片_20220309070102.png

块级作用域

块作用域是一个用来对之前的最小授权原则进行扩展的工具,将代码从在函数中隐藏信息扩展为在块中隐藏信息。

为了与其他主流语言靠近,块级作用域是ES6推出了let,const实现块级作用域。

微信图片_20220309070404.png 上面只是将变量d改为使用let声明,但是运行结果就发生了变化

微信图片_20220309070520.png 发生的原因就是使用var声明时,变量d的作用域在函数内。

而使用let声明时,作用域只在if代码块内。

面试攻略

这道题其实就是一个基础题。回答的关键是在描述的系统性上面。比如你硬说词法作用域和动态作用域组成了js的作用域体系就很奇怪。不在一个维度的描述会让人觉得描述不够系统和全面。