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

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

Leetcode33( 搜索旋转排序数组)

题目表述 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...

vue3 daterange正则踩坑

<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...