JavaScript作用域、闭包
文章目录
- 作用域、作用域链
- 作用域
- 作用域链
- 循环中的作用域
- 自由变量、闭包
- 自由变量
- 闭包的定义、表现、应用
- 如何确定在闭包中获取正确的变量
- 总结
作用域、作用域链
作用域
编程语言中存储、访问、修改变量当中的值是一项基本能力、存储变量、访问变量必须按照一定的规则,这套规则就是作用域。JavaScript中的作用域可分为三种:全局作用域、函数作用域、块作用域
- 全局作用域
在任何函数之外的顶层作用域,
全局可使用,如windows对象,document对象, 全局变量在全局作用域、函数作用域和块作用域里都可以获取到。
// 全局作用域var temp = 'A'; // 函数作用域function showTemp() {console.log(temp);}console.log(temp) // AshowTemp(); // A// 块作用域{temp = 'B'}console.log(temp) // B
- 函数作用域
函数中定义的作用域,只能在
当前函数中使用。
// 函数作用域function showTemp() {var temp = 'A'console.log(temp);}showTemp(); // Aconsole.log(temp) // 报错: temp not defined
- 块作用域
- ES6 新增的两个用于声明变量的新关键词
let和const。这两个关键字定义的变量如果处于大括号 { } 中,大括号中的变量就形成了一个块作用域。- 在
if/while/for等的大括号{ }里也形成了一个块作用域。
{let temp = 'A'}{console.log(temp) // 报错: temp not defined} console.log(temp) // 报错: temp not defined
作用域链
实际工程中,通常会使用多种作用域。当在当前作用域中无法找到目标变量时,就会向上级作用域寻找,这一层层向上的过程称为
作用域链。
const A = 1;function printSum(A) {const B = 2console.log(A + B)} printSum(A) // 3
上面是一个简单的示例,printSum函数中找到了需要的变量 B ,但是找不到变量 A ,于是沿着 作用域链 找到了 全局作用域 的目标变量A。
循环中的作用域
for (var i = 0; i < 5; i++) {setTimeout(function () {console.log(i);}, 1000);}
上面是一道经典的面试题目,最终会输出五个5,根据作用域的理论,在function中找不到变量i,当向上层寻找时,for循环里的i早已经执行到 i=5, 函数在延迟执行后取到的i只会是5。要实现预计的0-4打印效果,可以在 setTimeout 外面再套一层函数,或者在循环中使用let:
var print = function (i) {setTimeout(function () {console.log(i);}, 1000);};for (var i = 0; i < 5; i++) {print(i); // 会去print函数的作用域去寻找变量 i}// 0 1 2 3 4for (let i = 0; i < 5; i++) {setTimeout(function () {console.log(i);}, 1000);}// 0 1 2 3 4
自由变量、闭包
自由变量
- 定义:某变量 a 在作用域 A 中被使用,却没有在该作用域中被定义,需要沿
作用域链寻找,则对于作用域A来说,a是一个自由变量。- 自由变量确定:沿
作用域链向上级作用域一层层寻找,直到找到;若在全局作用域都没找到,会报错:xxx is not defined。
闭包的定义、表现、应用
如果一个函数引用了
自由变量,即该函数使用了某变量,但它既 不是函数参数、也不是函数内部定义的变量,则该函数就叫闭包。
闭包通常有两种表现:函数作为返回值、 函数作为参数被传递。
- 函数作为返回值
function closure() {const a = 100// 返回值函数return function () { console.log(a) // 100}} // 把返回值函数赋给fnconst fn1 = closure() fn1()
- 函数作为参数被传递
function closure() {const a = 100// 返回值函数return function () { console.log(a) // 100}} // 把返回值函数赋给fnconst fn1 = closure() fn1()
通过上述描述其实可以看到:闭包是作用域应用的一种特殊表现形式。那么,闭包到底有什么作用呢?一句话:闭包可以使变量仅在对象内部生效,无法从外部触及,只提供API,从而保护数据 。
举例一: 闭包隐藏数据,不能直接修改数据
function cache() {const data = {} // data是在函数cache作用域中被定义的,全局中未定义return {set: function (key, val) {data[key] = val},get: function (key) {return data[key]}}}const data = cache()data.set('name', 'jackeroo')const data_name = data.get('name')console.log(data_name) // jackerooconsole.log(data.name) // undefiend 无法直接获取name属性
举例二: 创建一个User对象,能够调取它的login方法获取用户名和密码,也能够直接访问该用户的用户名,但是不能取到该用户的密码
const User = function () {let _password;return class User {constructor(name, password) {this.userName = name;_password = password;}login() {console.log(`使用账号:${this.userName}, 密码:${_password}进行登录`)}}}()const theUser = new User('jackeroo', 123)theUser.login() // 使用账号:jackeroo, 密码:123进行登录console.log(theUser.userName) // jackerooconsole.log(theUser.password, theUser._password) // undefined undefined
如何确定在闭包中获取正确的变量
⭐在函数定义的地方向上级作用域查找,注意是函数定义的地方而不在函数执行处
// 示例1
function create(){const a = 100return function (){ // 函数的定义处console.log(a) }
}
const a = 200
const fn1 = create() // 函数执行处
fn1()//100// 示例2
function print(fn2){ const b = 200fn2() //函数执行处
}
const b = 100
function fn2(){ //函数定义处console.log(b)
}
print(fn2) // 100// 示例3
const c = 1;
function test(){a = 2;return function(){ // 函数定义处console.log(a);}var a = 3; // 变量提升 => var a = 2
}
test()(); // 2
通过以上三个例子再次强调:闭包/所有自由变量的查找是在函数定义的地方向上级作用域查找,而不是在函数执行的地方!!!
总结
作用域、作用域链
- 作用域
- 作用域链
自由变量、闭包
- 自由变量
- 闭包的定义、表现、应用
如何确定在闭包中获取正确的变量
闭包中的自由变量的查找是在函数定义的地方向上级作用域查找
相关文章:
JavaScript作用域、闭包
文章目录作用域、作用域链作用域作用域链循环中的作用域自由变量、闭包自由变量闭包的定义、表现、应用如何确定在闭包中获取正确的变量总结作用域、作用域链 作用域 编程语言中存储、访问、修改变量当中的值是一项基本能力、存储变量、访问变量必须按照一定的规则࿰…...
JavaScript Date(日期) 对象
JavaScript Date 对象是 JavaScript 中用于处理日期和时间的内置对象。它可以用于获取当前时间、设置日期和时间、计算日期和时间之间的差异、以及将日期和时间格式化为各种字符串格式。在本文中,我们将详细介绍 JavaScript Date 对象的作用和在实际工作中的用途。 …...
rust过程宏 proc-macro-workshop解题-4-sorted
名字版本号rust1.69.0OSubuntu 22.04这一大关卡介绍的是属性式过程宏。 第一关:01-parse-enum 还是简单的看我们是否已经实现了一个属性式过程宏的空架子,如果有这个空架子,就直接通过了。 use proc_macro::TokenStream; use proc_macro2; use syn;#[proc_macro_attribut…...
数据结构与算法—队列
队列 队列介绍 有序列表,可以用数组或者链表实现。遵循先进先出原则。 数组实现队列 public class ArrayQueue {public static void main(String[] args) {ArrayQueue queue new ArrayQueue(3);// 接收用户输入char key ;Scanner sc new Scanner(System.in);…...
AcWing3416.时间显示——学习笔记
目录 题目 代码 AC结果 思路 关键步骤 题目 3416. 时间显示 - AcWing题库https://www.acwing.com/problem/content/description/3419/ 代码 import java.util.Scanner;public class Main {public static void main(String[] args){Scanner input new Scanner(System.in…...
贴吧手机端防删图GIF动态图制作解析
贴吧存活 思路技术运气 1:防删图不是存活的绝对因素,除了防删图,还有账号,ip,内容,吧的问题 2:一个图不是每个吧都可以发 3:一个贴不被删不仅仅看图片 4:有时候运气也很…...
iOS接入Google登录
1.在Google Cloud后台配置客户端ID 首先要在 Google Cloud 中创建一个项目。新创建的Project需要先配置同意屏幕。一共有4步骤需要配置。 1.OAuth 同意屏幕 User Type选择"外部"进行创建。填写必必要的信息,应用名称、用户支持电子邮件地址、开发者电子邮…...
【C语言】大小端字节序问题
一、大小端字节序问题 大小端是由CPU决定的,大小端可以理解为字节顺序,所以大小端全称叫大端字节序、小端字节序。其实大端、小端这两个词是从《格列佛游记》里出来的。《格列佛游记》有一段讲的是吃鸡蛋是从大的那头敲开还是小的那头敲开的问题…...
Linux | 网络通信 | 序列化和反序列化的讲解与实现
文章目录为什么要序列化?协议的实现服务端与客户端代码实现为什么要序列化? 由于默认对齐数的不同,不同的平台对相同数据进行内存对齐后,可能得到不同的数据。如果直接将这些数据进行网络传输,对方很可能无法正确的获…...
C#的委托原理刨析and事件原理刨析和两者的比较
什么是委托委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。 在实例化委托时,你可以将其实例与任何具有兼容参数和返回类型的方法进行绑定。 你可以通过委托实例调用方法。简单的理解,委托是方法的抽象类,它定…...
Redis学习【8】之Redis RDB持久化
文章目录Redis 持久化1 持久化基本原理2 RDB(Redis DataBase) 持久化2.1 持久化的执行2.2 手动 save 命令2.3 手动 bgsave 命令2.4 自动条件触发2.5 查看持久化时间3 RDB 优化配置3.1 save3.2 stop-write-on-bgsave-error3.3 rdbcompression3.4 rdbchecksum3.5 sanitize-dump-p…...
SpringSecurity认证
文章目录登陆校验流程依赖yaml实现建表、工具类、实体类加密器、AuthenticationManager登录逻辑登录过滤器、配置过滤器登出登陆校验流程 认证 登录: ①自定义登录接口 调用ProviderManager的方法进行认证 如果认证通过生成token,根据userId把用…...
Socket套接字
概念 Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程。 分类 Socket套接字主要针对传输层协议划分为如下三类: 流套接字:使用传输层TCP…...
mysql详解之innoDB
索引 Mysql由索引组织,所以索引是mysql多重要概念之一。 聚簇索引 InnoDB和MyISAm一样都是采用B树结构,但不同点在于InnoDB是聚簇索引(或聚集索引),将数据行直接放在叶子节点后面。 这里可能存在一个误区࿱…...
电信运营商的新尝试:探索非通信领域的发展
近年来,随着电信运营商竞争的日趋激烈和网络建设的成本不断攀升,许多电信运营商已经开始缩减IT投资。然而,在如此情况下,电信运营商仍然需要寻找新的增长机会。那么,在持续缩减IT投资的情况下,电信运营商可…...
第07章_单行函数
第07章_单行函数 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 1. 函数的理解 1.1 什么是函数 函数在计算机语言的使用中贯穿始终,函数的作用是什么呢?它可以把我们经…...
Echarts实现多柱状图重叠重叠效果
有两种重叠效果: 1. 多个柱子重叠为一个 2. 多个柱子重叠为两组 第一种,图例: 这个灰色不是阴影哦, 是柱子. 1. 使用详解 (1) series.Z 折线图组件的所有图形的 z 值。控制图形的前后顺序。 z 值小的图形会被 z 值大的图形覆盖。z 相比 zlevel 优先级更低,而且不会…...
PHP学习笔记(一谦四益)
前言 上一篇文章 PHP学习笔记(观隅反三)分享了数组的知识,这篇文章接着分享和数组相关的算法。 算法效率 算法效率分为两种:第一种是时间效率,第二种是空间效率。时间效率被称为时间复杂度,而空间效率被称…...
Jvm -堆对象的划分
堆对于一个jvm进程来说是唯一的,一个进程只有一个jvm,但是进程半酣多个线程,多个线程共享一个堆。 也就是说,一个jvm实例只存在一个堆,同时对也是Java内存管理的核心区域。 Java堆区域的大小在jvm启动时就已经被确定…...
2023美赛F题讲解+数据领取
我们给大家准备了F题的数据,免费领取!在文末 国内生产总值(GDP)可以说是一个国家经济健康状况最著名和最常用的指标之--。它通常用于确定一个国家的购买力和获得贷款的机会,为各国提出提高GDP的政策和项目提供动力。GDP“衡量一个国家在给定时间段内生产…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...
