当前位置: 首页 > 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…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

Qemu arm操作系统开发环境

使用qemu虚拟arm硬件比较合适。 步骤如下&#xff1a; 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载&#xff0c;下载地址&#xff1a;https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效&#xff0c;稳定&#xff0c;易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...

Unity VR/MR开发-VR开发与传统3D开发的差异

视频讲解链接&#xff1a;【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...