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“衡量一个国家在给定时间段内生产…...
AceCommon:Arduino嵌入式零堆分配轻量C++工具库
1. AceCommon 库概述:面向嵌入式 Arduino 的轻量级底层工具集AceCommon 是一个专为资源受限的微控制器平台(尤其是 Arduino 生态)设计的零依赖、低开销 C 工具库。其核心设计哲学是“小而精、无侵入、可复用”。与常见的功能臃肿、依赖繁杂的…...
3大核心功能:让iOS推送调试效率提升10倍的SmartPush工具全解析
3大核心功能:让iOS推送调试效率提升10倍的SmartPush工具全解析 【免费下载链接】SmartPush SmartPush,一款iOS苹果远程推送测试程序,Mac OS下的APNS工具APP,iOS Push Notification Debug App 项目地址: https://gitcode.com/gh_mirrors/smar/SmartPush 一、问…...
PyQt新手必看:Fluent Widgets vs PyQtGraph,哪个更适合你的GUI项目?
PyQt新手指南:Fluent Widgets与PyQtGraph的深度对比与选型策略 当你第一次踏入PyQt GUI开发的世界,面对琳琅满目的框架选择,是否感到迷茫?Fluent Widgets和PyQtGraph这两个名字可能已经出现在你的搜索列表中,但它们究竟…...
基于Python的律师事务所案件管理系统毕业设计
博主介绍:✌ 专注于Java,python,✌关注✌私信我✌具体的问题,我会尽力帮助你。一、研究目的本研究旨在开发一套基于Python的律师事务所案件管理系统,以满足现代法律事务处理的高效性和智能化需求。具体研究目的如下: 首先…...
GD32F4开发板GD-LINK驱动安装与Keil配置全攻略(附常见问题解决)
GD32F4开发板GD-LINK驱动安装与Keil配置全攻略(附常见问题解决) 第一次拿到GD32F4开发板时,很多开发者都会遇到驱动安装失败、Keil识别不到芯片的问题。这些问题看似简单,却可能让新手折腾好几个小时。本文将用最直白的方式&#…...
PyTorch实战(38)——深度学习模型可解释性
PyTorch实战(38)——深度学习模型可解释性0. 前言1. PyTorch 模型可解释性2. 训练手写数字分类器3. 可视化模型卷积核4. 可视化特征图小结系列链接0. 前言 在本专栏中,我们已经构建了多种深度学习模型来完成不同任务,包括手写数字…...
计算机毕设 java 基于 Android 的医疗预约系统的设计与实现 SpringBoot 安卓智能医疗预约挂号平台 JavaAndroid 医患预约诊疗管理系统
计算机毕设 java 基于 Android 的医疗预约系统的设计与实现 53m069,末尾的数字和英文也要加上 (配套有源码 程序 mysql 数据库 论文)本套源码可以先看具体功能演示视频领取,文末有联 xi 可分享随着信息技术的飞速发展和医疗需求的…...
系统焕新:Win11Debloat工具让Windows性能提升51%的全方位优化方案
系统焕新:Win11Debloat工具让Windows性能提升51%的全方位优化方案 【免费下载链接】Win11Debloat 一个简单的PowerShell脚本,用于从Windows中移除预装的无用软件,禁用遥测,从Windows搜索中移除Bing,以及执行各种其他更…...
2026年AI前20岗位薪酬出炉!搞AI大模型的远超同行?
AI相关,细分技术领域,薪资前20岗位,都有哪些。 今天这篇文章与铁铁们分享一下。 1 薪资榜单 如下图所示,排名第一:深度学习算法工程师,平均月薪达到3万1千; 排名第二的架构师,薪资与…...
从Python转C++必看:C++20的starts_with/ends_with和Python有何不同?5个易错点详解
从Python转C必看:C20的starts_with/ends_with和Python有何不同?5个易错点详解 当你在Python中熟练使用startswith()和endswith()多年后,突然切换到C20的starts_with和ends_with,可能会觉得"这不就是换个语法吗?&q…...
