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

735 阅读2分钟

作用域你懂多少种?

  • 全局作用域
  • 函数作用域
  • 块作用域
  • 词法作用域
  • 动态作用域
  • 全局作用域
  • 作用域链

作用域

作用域(英文:scope)是据名称来查找变量的一套规则,可以把作用域通俗理解为一个封闭的空间,这个空间是封闭的,不会对外部产生影响,外部空间不能访问内部空间,但是内部空间可以访问将其包裹在内的外部空间。

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

image-20220114233134114

静态作用域与动态作用域

静态作用域(static scope) 与 词法作用域(lexical scope)

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

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

 1.静态作用域
    var firstOne = 10;
    function fn (){
        var firstTwo = 1;
        console.log(firstOne + firstTwo)
    }
    fn()

动态作用域(dynamic scope)

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

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

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

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

函数作用域 与 块级作用域

函数作用域:指在函数内声明的所有变量在函数体内始终是可见的,可以在整个函数的范围内使用及复用。

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() //a b c d

作用域链

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

块级作用域

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

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

var a = 'a'
function f1() {
    var b = 'b'
    function f2() {
        var c = 'c'
        function f3() {
          if(true) {
            debugger
          	let d = 'd' // var 改为 let
        	}
          debugger
          console.log(a, b, c, d)
        }
      	f3()
    }
  	f2()
}
f1()

上面只是将变量d改为使用let声明 image.png 运行结果出现变化

image.png