likes
comments
collection
share

每日一学: JS中的作用域

作者站长头像
站长
· 阅读数 59

在编程语言中,特别是像JavaScript这样的语言中,作用域是一个非常重要的概念,它决定了变量、函数以及其它标识符在何处可以被访问

首先

在了解作用域之前,让我们先来了解一些JS中的基础概念

类型

在JS中有以下几种基础类型

  • Number: 用于存储整数或浮点数,例如 42 或 3.14
  • String: 用于存储文本,需要用单引号 ' ' 或双引号 " " 包围,例如 'Hello, world!'
  • Boolean: 表示真或假的值,只有两个可能的值:true 和 false
  • Undefined: 表示变量已被声明但没有被赋值,默认的初始值。
  • Null: 表示一个刻意的空值或缺少对象值,它是一个特殊的原始值。 代码表示为:
var str = 'hello world'; // string 字符串类型
var num = 123; // Number 数字
var flag = true; // Boolean 布尔类型
var u = undefined;  // 强调未定义
var n = null; // 强调为空值

以下引用类型:

  • Object: 用于存储键值对集合,可以是复杂的数据结构。所有非原始类型都归为此类,包括数组(Array)、函数(Function)、日期(Date)、正则表达式(RegExp)等。
  • Array: 特殊类型的对象,用于存储有序的数据集合。
  • Function: 在JavaScript中,函数也是对象,可以被赋值给变量、作为参数传递给其他函数或作为其他函数的返回值。 代码表示为:
var obj = {}; // Object 对象
var arr = []; // Arrar 数组
var fn = function(){}// function 函数

判断 条件语句

  1. if 语句: 基础的条件判断结构,如果条件为真,则执行相应的代码块。

    if (条件) {
        // 条件为真时执行的代码
    }
    
  2. if...else 语句: 在条件为真时执行一块代码,在条件为假时执行另一块代码。

    if (条件) {
        // 条件为真时执行的代码
    } else {
        // 条件为假时执行的代码
    }
    
  3. if...else if...else 语句: 用于测试多个条件,依次检查每个条件,直到找到第一个为真的条件并执行对应的代码块。

    if (条件1) {
        // 条件1为真时执行的代码
    } else if (条件2) {
        // 条件1为假且条件2为真时执行的代码
    } else {
        // 所有条件都为假时执行的代码
    }
    
  4. switch 语句: 当有多重分支选择时使用,基于不同的情况执行不同的代码块。每个case后面通常跟着一个break语句,以防止代码穿透到下一个case

    switch (表达式) {
        case1:
            // 表达式等于值1时执行的代码
            break;
        case2:
            // 表达式等于值2时执行的代码
            break;
        default:
            // 没有匹配的case时执行的代码
    10}
    

判断语句

  1. for循环: 通常用于已知循环次数的情况。其基本语法结构如下:

    for (初始化表达式; 条件表达式; 更新表达式) {
        // 循环体(需要重复执行的代码)
    }
    
    • 初始化表达式:在循环开始前执行一次,通常用于设置循环变量。
    • 条件表达式:在每次循环迭代前检查,如果为真,则执行循环体。
    • 更新表达式:在每次循环迭代后执行,通常用于更新循环变量。
  2. while循环: 当给定条件为真时,重复执行代码块。语法如下:

    while (条件表达式) {
        // 循环体(需要重复执行的代码)
    }
    
    • 条件表达式:在每次循环开始前评估,只要条件为真,循环就会继续。

好的,基础知识了解完毕,下面进入正题。

作用域

在JS中,在代码执行时,先要进行编译

就像执行var a = 1这一句代码,在v8引擎(谷歌内置JS执行引擎,node就是类似的引擎)眼里,他会先编译这段代码将这段代码分解为这样一段过程var ,a ,= ,1,这叫解析,然后又重新生成代码var a = 1,然后把这段过程的结果交给执行部分,执行代码。我们写出的代码,首先就会经过这样的编译,如果我们的代码就是简单的输入输出,那么就是流畅的编译->执行,但一旦有了特殊的需求,这样简单的过程明显无法满足需求,这个时候作用域的作用就出来了,我们来看这一段代码:

var a = 1

function foo(){
   var a = 2
}
foo()
console.log(a);

这段代码在控制台中的输出是什么呢?输出a的值我们当然知道,问题是a的值是多少呢?是2吗?我刚开始也是这么认为的,这里不是有一个函数把a的值又赋为了2吗?但最后却输出了1,,很奇怪对吧,这就是作用域的作用了,这里我们先了解一个概念,那就是作用域主要分为了

  1. 全局作用域:在程序的最外层定义的变量拥有全局作用域,这意味着从定义处开始,直到程序结束,都可以访问到这些变量。在浏览器环境中,全局变量属于window对象(在Node.js中则是global对象)的一部分。尽量避免过多使用全局变量,因为它们容易造成命名冲突和数据污染。
  2. 函数作用域:也称为局部作用域,当在一个函数内部定义变量时,这个变量就只在这个函数内部可见。每次函数调用都会创建一个新的作用域,因此相同名称的变量在不同的函数中互不影响。

在代码执行时会先考虑全局,再考虑函数

然后我们来模拟一下这段代码到底是怎么执行的。

首先,在董事长面前放着这一份代码,“董事长”表示我看不懂这一份代码,“秘书”你来帮我安排一下怎么去执行这段代码。然后“秘书”就来分析这段代码了,欸,然后“秘书”就在他的小本本上开始记了

首先

每日一学: JS中的作用域

好了,这里“秘书”的工作就完成了,在第一步全局作用域编译时,“秘书”首先识别到了a这个数据,但“秘书”又不能执行,所以在“秘书”这里就定义为了undefined,未被定义但应该有个值,然后就是foo,这是个function函数对象,然后完了,那么就要问了,函数里面呢?后面的函数调用呢?控制台输出呢?

所以这就是全局作用域和函数作用域的区别了,函数在这时的“秘书”眼里是空的,是需要定义的,有东西但我识别不了的意思。

而函数调用以及控制台输出是要执行部分干的事了。

好了,“秘书”把这份笔记交给了“董事长”,说你按照这里执行就可以了,“董事长”说好的,这就来执行,于是就有了

每日一学: JS中的作用域 “董事长”将a赋值为1后,到foo()时愣住了,说,欸,秘书,这函数你还没告诉我怎么搞呢,你去帮我搞一下。 好,“秘书”就去搞函数了,就有了

每日一学: JS中的作用域

函数里就一个给a赋值的操作对吧,于是秘书又交给了“董事长”,然后就又有了

每日一学: JS中的作用域

好了,调用函数结束,到了最后的输出a的阶段了,那么,我们现在有两个a,输出那个呢?输出全局的那个1 这里我们就有了,作用域的一个特点:

内部作用域可以访问外部作用域,反之则不行

为什么呢?因为这是的关系先进后出,后进先出,所以在这时,a的输出无法调用函数作用域内的2,于是输出了处在全局作用域的a=1

除去这两个作用域,还有

  1. 块级作用域:在一些现代编程语言中(如JavaScript ES6引入了letconst关键字),支持块级作用域。这意味着在if语句、for循环或者任何一对大括号{}内定义的变量,其作用域仅限于那个块内部。这有助于减少变量泄露到外部作用域的可能性,增强代码的模块性和可维护性。

就是说{} + let||const就是块级作用域,而且只作用于这两个关键字,不会影响其他的关键字

  1. 词法作用域(静态作用域):JavaScript采用词法作用域,这意味着变量的作用域在代码编写时就已经确定,而非在运行时决定。这意味着函数内部可以访问包含它的函数(父作用域)中的变量,即使父函数已经执行完毕。

变量声明的地方-- 所处的作用域就是词法作用域,就像是我处在这个房间内,那么对于这句话中的我来说,这个房间就是我的词法作用域。

  1. 欺骗词法作用域

(1)eval() 让原本不属于这里的代码,变得好像天生就定义在这里一样

function foo(a,str){
    eval(str);

    console.log(a,b);

}

foo(1,'var b = 2')

就像是这段代码的str,它就被eval()执行为了foo中的属性b=2

(2)with(){} 当修改对象中不存在的属性时,这个属性会被泄露到全局,变成全局变量

结语

作用域理解起来稍难,但请记住,实践是学习编程的最佳途径,不断尝试、勇于探索,我们将能更熟练地运用这些知识解决实际问题。在编程的旅途中,遇到挑战是常有的事,请坚持下去,每解决一个问题,我们就会变得更加强大。最后,希望我的理解能帮助到你,我是Ace,我们下次分享再见!!!

转载自:https://juejin.cn/post/7372441501609656346
评论
请登录