当前位置: 首页 > news >正文

块级作用域的理解

块级作用于的概念

由一对花括号{}中的语句集都属于一个块,在这个{}里面包含的块内定义的所有变量在代码块外都是不可见的,因此称为块级作用域。
作用域永远都是任何一门语言的重中之中,因为它控制着变量和参数的可见性和生命周期。讲到这里,首先要理解两个概念:块作用域和函数作用域。什么是块级作用域呢?

任何一对花括号({})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。

函数作用域就更好理解了定义在函数中的参数和变量在函数外是不可见的。

作用域分析


function fn1(x) {
  var a = 0;
  let b = 0;
  {
    var c = 1; // 未用let或const,不形成c的块作用域,依然是bar的函数作用域
    let d = 1; // d形成块作用域,只可在当前代码块中访问
  }
  function fn() {
    var e = 2;
    let g = 2;
    console.log('a:', a)
    console.log('b:', b)
    console.log('c:', c) // 访问外部作用域中的a/b/c,形成闭包
    // console.log('d:', d) // d is undefined
  }
  f()
}
fn1(5)


代码执行进入fn1函数时的作用域如下:

  1. 在fn1中用var定义的a
  2. 在fn1中用let定义的b
  3. 在代码块中用var定义的c
  4. 在fn1中定义的函数fn
  5. fn1形参x


当前执行上下文栈是 [全局执行上下文, fn1执行上下文]

代码进入代码块时的作用域

当前执行上下文栈是 [ 全局执行上下文,fn1执行上下文, 块作用域1]

代码进入fn函数时的作用域

在fn中用var声明的e
在fn中用let声明的f
在fn中有对fn1变量对象的引用,形成闭包


当前执行上下文栈是 [ 全局执行上下文,fn1执行上下文(闭包), fn执行上下文]

for遍历中的var与let


function bar() {
  var fnArr1 = []
  var fnArr2 = []
  var fnArr3 = []
  for(var i = 0; i < 5; i++) {
    fnArr1.push(function() {
      return i
    })
  }
  for(var k = 0; k < 5; k++) {
    (function(k) {
      fnArr2.push(function() {
        return k
      })
    })(k)
  }
  for(let j = 0; j < 5; j++) {
    fnArr3.push(function() {
      return j
    })
  }
  console.log('i:', i) // 5
  console.log('fnArr1:', fnArr1.map(x => x())) // [4, 4, 4, 4, 4]
  console.log('--------')
  console.log('k:', k) // 5
  console.log('fnArr2:', fnArr1.map(x => x())) // [0, 1, 2, 3, 4]
  console.log('--------')
  console.log('j:', j)
  console.log('fnArr3:', fnArr1.map(x => x()))
}


在for循环中使用var声明表达式变量


var声明变量不具有块作用域特性,它声明的变量作用域为当前作用域,在循环中i会被反复覆盖,所以当循环遍历结束后,i的值为最后一次遍历的值,即在这里为5。

var fnArr1 = []
for(var i = 0; i < 5; i++) {
  fnArr1.push(function() {
    return i
  })
}
console.log('fnArr1:', fnArr1.map(x => x())) // [5, 5, 5, 5, 5]

在for循环中使用var声明表达式变量且用立即执行函数

通过传递参数到立即执行函数,传递的参数是非引用类型变量,所以已然切割了与外面变量k的联系,即第一次循环传递的是数字0, 第二次循环传递的是数字1 … 以此类推,所以遍历执行数组的函数会返回一个递增的数组。 

var fnArr2 = []
for(var k = 0; k < 5; k++) {
  (function(k) {
    fnArr2.push(function() {
      return k
    })
  })(k)
}
console.log('fnArr2:', fnArr1.map(x => x())) // [0, 1, 2, 3, 4]
 

 在for循环中使用let声明表达式变量


let声明的变量会有块级作用域的特点,所以在for循环表达式中使用let其实就等价于在代码块中使用let,也就是说

for(let j = 0; j < 5; j++) 这句话的圆括号之间,有一个隐藏作用域
for(let j = 0; j < 5; j++) { 循环体 } 在每次执行循环体之前,js引擎会把j在循环体的上下文中重新声明及初始化一次


var fnArr3 = []
for(let j = 0; j < 5; j++) {
  fnArr3.push(function() {
    return j
  })
}

// js引擎会处理成
for(let j = 0; j < 5; j++) {
  let t = j
  fnArr3.push(function() {
    return t
  })
}
console.log('fnArr3:', fnArr1.map(x => x())) // [0, 1, 2, 3, 4]


拓展


function fn() {
  var fnArr = []
  for (let p = { i: 0 }; p.i < 5; p.i++) {
    fnArr.push(function() {
      return p.i
    })
  }
  console.log(fnArr.map(x => x())) // [5, 5, 5, 5, 5] 为什么??
}
fn()


按照上面的理解打印出来的应该是[0, 1, 2, 3, 4]才对,但是为什么与期望不符呢?这与浅拷贝/深拷贝的问题有关了

js引擎会把上面的循环处理为以下代码:

for (let p = { i: 0 }; p.i < 5; p.i++) {
  let k = p // 这里为引用类型变量的赋值
  fnArr.push(function() {
    return k.i
  })
}


js引擎在循环体中用let声明了一个变量k=p,这里p为引用类型变量*{ i: 0 }*, 即这里声明的k是对p对象的引用。所以执行fnArr中的函数,最终返回的是p的i属性;而p.i在一次次循环后已经自增为5,所以最终打印结果都是5。

那如何改写上面代码来实现想要的结果呢?

function fn() {
  var fnArr = []
  var o = { i: 0 }
  for (let p = o.i; p < 5; p++) {
    fnArr.push(function() {
      return p
    })
  }
  console.log(fnArr.map(x => x())) // [0, 1, 2, 3, 4]
}
fn()

相关文章:

块级作用域的理解

块级作用于的概念 由一对花括号{}中的语句集都属于一个块&#xff0c;在这个{}里面包含的块内定义的所有变量在代码块外都是不可见的&#xff0c;因此称为块级作用域。 作用域永远都是任何一门语言的重中之中&#xff0c;因为它控制着变量和参数的可见性和生命周期。讲到这里&…...

【GitLab、GitLab Runner、Docker】GitLab CI/CD 应用

安装Gitlab开源版 官方文档-安装Gitlab 使用Docker安装 sudo docker run --detach \--hostname gitlab.example.com \--env GITLAB_OMNIBUS_CONFIG"external_url http://${ip}:9999/; gitlab_rails[gitlab_shell_ssh_port] 8822;" \--publish 443:443 --publish 99…...

Linux文本编辑器vim使用和配置详解

vim介绍 ​ vim是Linux的一款文本编辑器&#xff0c;可以用来编辑代码&#xff0c;而且支持语法高亮&#xff0c;还可以进行一系列配置使vim更多样化。也可以运行于windows&#xff0c;mac os上。 ​ vim有多种模式&#xff0c;但目前我们只介绍绝大多数场景用的到的模式&…...

港科夜闻|香港科大戴希教授被选为腾讯公司新基石研究员

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大戴希教授被选为腾讯公司“新基石研究员”。10月30日&#xff0c;作为目前国内社会力量资助基础研究力度最大的公益项目之一&#xff0c;“新基石研究员项目”揭晓了第二期获资助名单&#xff0c;来自13个城市28家…...

如何读懂深度学习python项目,以`Multi-label learning from single positive label`为例

Paper : Multi-label learning from single positive label Code 先读一读README.md 可能有意想不到的收获&#xff1b; 实验环境设置要仔细看哦&#xff01; 读论文 如何读论文&#xff0c;Readpaper经典十问 &#xff08;可能在我博客里有写&#xff09; How to read a …...

【面试】Kafka基础知识

定义 Kafka是一个分布式基于发布/订阅模式的消息队列 优点 解耦&#xff1a;上下游之间依赖解耦。缓冲/削峰&#xff1a;生产消息的速度和消费消息的速度不一致时&#xff0c;可以起到缓冲作用。异步&#xff1a;天然的异步处理机制&#xff0c;生产者把消息(任务)放进队列&…...

【入门Flink】- 06Flink作业提交流程【待完善】

Standalone 会话模式作业提交流程 代码生成任务的过程&#xff1a; 逻辑流图&#xff08;StreamGraph&#xff09;→ 作业图&#xff08;JobGraph&#xff09;→ 执行图&#xff08;ExecutionGraph&#xff09;→物理图&#xff08;Physical Graph&#xff09;。 作业图算子链…...

Linux 上的轻量级浏览器

导读大多数 Linux 桌面环境中包含的基本图像查看器可能不足以满足你的需要。如果你想要一些更多的功能&#xff0c;但仍然希望它是轻量级的&#xff0c;那么看看这四个 Linux 桌面中的图像查看器&#xff0c;如果还不能满足你的需要&#xff0c;还有额外的选择。 当你需要的不…...

肆[4],滤波

1&#xff0c;简介 1.1&#xff0c;Opencv提供滤波处理函数 方框滤波&#xff0c;BoxBlur函数 均值滤波(领域平均滤波)&#xff0c;Blur函数 高斯滤波&#xff0c;GaussianBlur函数 中值滤波&#xff0c;medianBlur函数 双边滤波&#xff0c;bilateralFilter函数 1.2&…...

Python 包管理器入门指南

什么是 PIP&#xff1f; PIP 是 Python 包管理器&#xff0c;用于管理 Python 包或模块。注意&#xff1a;如果您的 Python 版本是 3.4 或更高&#xff0c;PIP 已经默认安装了。 什么是包&#xff1f; 一个包包含了一个模块所需的所有文件。模块是您可以包含在项目中的 Pyth…...

2022年06月 Python(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试&#xff08;1~6级&#xff09;全部真题・点这里 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 第1题 如下所示的2行代码&#xff0c;最后print()函数打印出来的结果是&#xff1f;&#xff08; &#xff09; c [[赵大,…...

配置Raspberry自动连接WIFI,在无法查看路由器的校园网情况下使用自己电脑热点

1、开启电脑热点&#xff0c;并共享电脑WLAN2 打开控制面板->网络和Internet->网络连接 选择自己的校园网&#xff0c;我这里是WLAN2&#xff0c;右键属性&#xff0c;如下操作&#xff1a; 如果没有看到 本地连接*10类似的图标 则按如下操作&#xff1a;winx键&#x…...

#stm32整理(一)flash读写

以这篇未开始我将进行stm32学习整理为期一个月左右完成stm32知识学习整理内容顺序没有一定之规写到哪想到哪想到哪写到哪&#xff0c;主要是扫除自己知识上的盲区完成一些基本外设操作。 以stm32f07为例子进行flash读写操作 stm32flash简介 参考资料正点原子和野火开发手册 …...

windows10编译高版本openssl

参考文章 参考文章中的windows编译为低版本&#xff0c;在高版本的openssl编译中已经没有&#xff1a;“ms\do_ms.bat”这个脚本了&#xff0c;现记录下编译过程 1、准备工作 安装ActivePerl&#xff0c;安装后会自动写入环境变量&#xff0c;参照参考文章测试安装成功与否&a…...

Mac之NVM|通过brew安装、更新、卸载、重新安装nvm

文章目录 导文通过brew安装NVM通过brew更新NVM通过brew卸载NVM通过brew重新安装NVM 导文 Mac之NVM 通过brew安装、更新、卸载、重新安装 通过brew安装NVM brew install nvm通过brew更新NVM brew upgrade nvm通过brew卸载NVM brew uninstall nvm通过brew重新安装NVM brew re…...

react的状态管理有哪些方法?

在React中,有多种方法可以进行状态管理,以下是其中一些常见的方法: 1:使用React的内置状态(State): React组件可以通过使用 useState 钩子来管理内部的状态。它允许你在函数组件中定义和更新状态。例如: import React, { useState } from react;function MyComponent…...

AST注入-从原型链污染到RCE

文章目录 概念漏洞Handlebarspug 例题 [湖湘杯 2021 final]vote 概念 什么是AST注入 在NodeJS中&#xff0c;AST经常被在JS中使用&#xff0c;作为template engines(引擎模版)和typescript等。对于引擎模版&#xff0c;结构如下图所示。 如果在JS应用中存在原型污染漏洞&…...

【开题报告】基于uniapp的在线考试小程序的设计与实现

1.研究背景 随着社会的发展和科技的进步&#xff0c;网络技术被广泛应用于教育领域。在线教育已成为当今发展趋势之一&#xff0c;其中在线考试更是具有重要的意义。传统的考试方式不仅耗费大量人力物力&#xff0c;而且存在考试成果的保密问题。而在线考试可以使考试过程更加…...

使用pdf2image pdf转图片

安装poppler https://wenku.csdn.net/answer/1zxh8ckp6i from pdf2image import convert_from_path, convert_from_bytes import os# https://github.com/Belval/pdf2imageoutput_folder ./ dpi_value 600 pdf_start_page 1 # pdf显示的第一页 start_page 237 # 真实页码 p…...

非关系型数据库Redis的安装【Linux】及常用命令

前言 Redis&#xff08;Remote Dictionary Server&#xff09;是一种开源的内存数据库管理系统&#xff0c;它以键值存储方式来存储数据&#xff0c;并且支持多种数据结构&#xff0c;如字符串、哈希、列表、集合、有序集合等。Redis最初由Salvatore Sanfilippo开发&#xff0c…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...