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

简介: Day14 - 词法作用域、块级作用域、作用域链、静态动态作用域

那些年听说的作用域



  • 全局作用域


  • 函数作用域


  • 块作用域


  • 词法作用域


  • 动态作用域


  • 全局作用域


  • 作用域链


作用域


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


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


网络异常,图片无法展示
|


静态作用域与动态作用域


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


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


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


网络异常,图片无法展示
|


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


动态作用域(dynamic scope)


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


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 是指向的是函数运行时所在的环境,也就是说只有到了执行时才能确定。


扩展


其实动态与静态的问题在每种语言中都存在,


比如:


  • C++  动态联编与静态联编 - 虚函数


  • Java 动态编译与动态加载


函数作用域 与 块级作用域


下面我们细致的说一下函数作用域和块级作用域。


对于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标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链


网络异常,图片无法展示
|


块级作用域


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


为了与其他主流语言靠近,块级作用域是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声明


网络异常,图片无法展示
|


但是运行结果就发生了变化


网络异常,图片无法展示
|


发生的原因就是使用var声明时,变量d的作用域在函数内。


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


面试攻略


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


网络异常,图片无法展示
|


相关文章
|
14天前
|
JavaScript 前端开发
块级作用域和函数作用域有什么区别?
【10月更文挑战第29天】块级作用域和函数作用域在JavaScript中各有特点和用途。块级作用域提供了更精细的变量控制,有助于避免变量提升和意外的全局变量污染等问题;而函数作用域则在函数封装和模块化编程等方面有着重要的应用。在实际开发中,需要根据具体的需求和场景合理地选择使用哪种作用域来声明变量和组织代码。
|
14天前
|
存储 缓存 JavaScript
哪些情况适合使用块级作用域,哪些情况适合使用函数作用域?
【10月更文挑战第29天】块级作用域和函数作用域在不同的场景下各有优势,合理地选择和运用这两种作用域可以使JavaScript代码更加清晰、高效和易于维护。在实际开发中,需要根据具体的业务需求、代码结构和编程模式来决定使用哪种作用域,或者在适当的情况下结合使用两者,以达到最佳的编程效果。
|
1月前
|
自然语言处理 JavaScript 前端开发
词法作用域和静态作用域有什么区别
【10月更文挑战第12天】词法作用域和静态作用域有什么区别
|
1月前
|
自然语言处理 JavaScript 前端开发
词法作用域
【10月更文挑战第12天】词法作用域
|
1月前
|
自然语言处理 JavaScript 前端开发
什么是词法作用域
【10月更文挑战第12天】什么是词法作用域
|
1月前
|
JavaScript 前端开发
作用域和作用域链及预解析
作用域和作用域链及预解析
20 4
|
2月前
|
Java
作用域
作用域
19 2
|
2月前
C 作用域详解
在 C 语言中,作用域决定了变量和函数的可见性和生命周期,包括块作用域、函数作用域、文件作用域和全局作用域。块作用域内的变量仅在块内有效,函数作用域内的变量在整个函数内有效,文件作用域内的全局变量和函数在整个文件内有效,而全局作用域内的变量和函数在整个程序运行期间有效。作用域的优先级遵循局部变量优先的原则,局部变量会遮蔽同名的全局变量。变量的生命周期分为局部变量(函数调用时创建和销毁)、全局变量(程序开始时创建和结束时销毁)以及静态变量(整个程序期间有效)。理解作用域有助于避免命名冲突和错误,提高代码的可读性和可维护性。
|
6月前
|
JavaScript 前端开发 Python
函数与作用域
编程中的函数与作用域概念。函数是可重用的代码块,能提高代码的可读性、可维护性和复用性。基础用法包括定义、调用和返回值。高级用法涉及函数嵌套、匿名函数(lambda函数)和装饰器。装饰器能在不修改原函数代码的情况下添加功能。 作用域决定了变量的可见范围,从内到外是局部、嵌套、全局和内置作用域。闭包是能访问外部函数变量的内部函数,即使外部函数执行完毕,闭包仍能保留其状态。闭包常用于实现特殊功能,如记忆化和延迟执行。 立即执行函数表达式(IIFE)是JavaScript中的模式,用于创建私有作用域和防止变量污染全局。IIFE常用于封装变量、避免命名冲突以及实现模块化和函数作为参数传递。
|
存储 JavaScript 前端开发
Javascript作用域 (局部作用域和全局作用域) 详细介绍
Javascript作用域 (局部作用域和全局作用域) 详细介绍
109 0