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

想品客老师的第七天:闭包和作用域

闭包之前的内容写在这里

环境、作用域、回收

首先还是数据的回收问题,全局变量一般都是通过关闭页面回收的;而局部变量的值不用了,会被自动回收掉

像这种写在全局里的就不会被主动回收捏:

      let title = '荷叶饭'function fn() {alert(title)}document.querySelector('button').addEventListener('click', fn)

求后盾人老师别举他那听不懂的栗子了。。。

在计算机里环境可以理解为一块内存的数据,就是块空间

  let title='荷叶饭'function show(){let url='#'}show()console.log(url)

外面用不了里面的变量

里面用得了外面的变量:

      let title = '荷叶饭'function show() {let url = '#孩子们我是个链接'function hd() {console.log(url)//里面可以访问外面}hd()}show()

函数环境生命周期

函数在调用之前的声明相对于建造城市的计划,调用函数相当于城市动工了,调用多次函数相当于建造多个一样的城市(开辟多块空间),但是不是同一个城市,彼此独立

function buildCity() {let city = {};return city;
}let city1 = buildCity(); // 创建第一个城市
let city2 = buildCity(); // 创建第二个城市
console.log(city1 === city2); // false,两个不同的城市

只有在显式修改共享状态时,才可能出现覆盖的情况。

let sharedCity = null;function buildCity() {sharedCity = {}; // 覆盖之前的 sharedCityreturn sharedCity;
}let city1 = buildCity(); // 创建并覆盖 sharedCity
let city2 = buildCity(); // 再次覆盖 sharedCity
console.log(city1 === city2); // true,因为 sharedCity 被覆盖了

如果一个函数不return,相当于没有被外部引用,每次调用都是单独创建新的一块:

      function hd() {let n = 1;return function sum() {// console.log(++n);let m = 1;function show() {console.log("m:" + ++m);console.log("n:" + ++n);};show()};}let a = hd();a();a();a();

n被return了,所以n++,但是m是独立的没有被外部调用,所以不++

输入被return,相当于被外部引用,所以多次调用m会在原来的基础上++:

     function hd() {let n = 1;return function sum() {// console.log(++n);let m = 1;return function show() {console.log("m:" + ++m);console.log("n:" + ++n);};};}let a = hd()();a();a();a();

延长了函数的生命周期

构造函数里的环境是什么

每执行一次构造函数就会创造出一个新的对象:

function Hd() {let n = 1;this.sum = function () {console.log(++n);};}let a = new Hd();a.sum();a.sum();let b = new Hd();b.sum();b.sum();

这方面和普通函数没什么区别:

块级作用域

没报错,这就说明这是两个块

        {let a = 1}{let a = 1}

var没有块作用域的原因居然是块作用域出的比var晚,推出let和const可以适用块作用域

let-const-var在for循环

var没有块的特性:

 for (var i = 1; i <= 3; i++) {console.log(i);}console.log(i)//可以访问

在for里写个定时器

如果是var的话:

 for (var i = 1; i <= 3; i++) {setTimeout(function () {console.log(i);}, 1000);}console.log(i);

当 setTimeout 的回调函数执行时,for 循环已经执行完毕,此时 i 的值已经变成了 4,所以所有回调函数都会输出 4

换成let结果就不一样了:

let是有块级作用域的概念,for里的定时器函数在i等于不同值的时候,会先向上一级找i,还没找到全局,就在父级找到i了,找到的i就等于此时i的值

  for (let i = 1; i <= 3; i++) {setTimeout(function () {console.log(i);}, 1000);}

var模拟块作用域

用定时器+立即执行函数模拟块作用域,每次循环创建一个新的作用域,从而捕获当前的 i 值,确保 setTimeout 回调函数输出正确的值。

for (var i = 1; i <= 3; i++) {(function (i) {setTimeout(function () {console.log(i);//1,2,3}, 1000);})(i);}

多级作用域嵌套

不想被清掉的函数可以放在数组里:

   let arr = [];for (var i = 1; i <= 3; i++) {arr.push(function () {return i;})}console.log(arr[2]());//4

但是i打印出来都是4,因为定时器比for执行的慢

可以保留作用域:

    let arr = [];for (var i = 1; i <= 3; i++) {(function (i) {arr.push(function () {return i;});})(i)//把i传过去// console.log(i);}console.log(arr[2]())//3

闭包

哪个傻逼弹幕说的闭包和函数没有必然关系的

闭包(Closure)是 JavaScript 中一个非常重要的概念,也是函数式编程的核心特性之一。闭包是指一个函数能够记住并访问它的作用域,即使这个函数在其作用域之外执行

求后盾人老师不要再温故而知新了

在做一个筛数组元素的函数的时候,可以发现筛的这个方法可以单独提出来:

    let arr = [1, 23, 4, 5, 6, 7, 8, 9, 21, 10];function between(a, b) {return function(v) {return v >= a && v <= b;};}console.log(arr.filter(between(3, 9)))// [4, 5, 6, 7, 8, 9]

本来筛不同区间的数是这么做的:

let hd = arr.filter(function (v) {return v >= 2 && v <= 9;});console.log(hd);// [4, 5, 6, 7, 8, 9]let a = arr.filter(function (v) {return v >= 6 && v <= 10;});console.log(a)//[6, 7, 8, 9, 10]

现在使用闭包结构,让匿名函数访问上层函数的参数,然后再返回当作filter函数的回调函数传入

也可以实现筛选商品的效果:

 let lessons = [{title: "媒体查询响应式布局",click: 89,price: 12},{title: "FLEX 弹性盒模型",click: 45,price: 120},{title: "GRID 栅格系统",click: 19,price: 67},{title: "盒子模型详解",click: 29,price: 300}];function between(a, b) {return function(v) {return v.price >= a && v.price <= b;};}console.table(lessons.filter(between(10, 100)));

应用

加深对闭包的印象:移动动画

按钮的 position 属性需要设置为 relative 或 absoluteleft 样式才能生效。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>button {position: absolute;}</style>
</head>
<button>点我 </button>
<button>溜了溜了。。。</button><body><script>let btns = document.querySelectorAll('button')btns.forEach(function (item) {item.addEventListener('click', function () {let left = 1setInterval(function () {item.style.left = left++ + 'px'//这里使用了闭包}, 10)})})</script>
</body></html>

如果多点几次,会触发频闪效果。。。会抖动

为什么呢?因为把left的定义写在了事件监听的函数里,所以每次点击left就会重新等于1

解决方案1就是把对left的定义放在外面一层:

     let btns = document.querySelectorAll('button')btns.forEach(function (item) {let left = 1item.addEventListener('click', function () {setInterval(function () {item.style.left = left++ + 'px'}, 10)})})

当你连点两次的时候,会发现按钮不抖动了,但是移动速度加快了!

为什么移动速度变快了?因为外面没有清除定时器,每点一下,就是新增了一个定时器,到最后越来越多的定时器再给按钮做left++的运算,所以越走越快!!

解决方法可以设置一个flag量,来判定是否创建过计时器:

 let btns = document.querySelectorAll('button')btns.forEach(function (item) {let left = 1let flag = falseitem.addEventListener('click', function () {if (!flag) {flag = truesetInterval(function () {item.style.left = left++ + 'px'}, 10)}})})

反过来把left放在里面,也不会出现频闪的情况(因为定时器只能开一个):

    let btns = document.querySelectorAll('button')btns.forEach(function (item) {let flag = falseitem.addEventListener('click', function () {if (!flag) {let left = 1flag = true//写在里面setInterval(function () {item.style.left = left++ + 'px'}, 10)}})})

利用闭包特性做购物排序:

let lessons = [{title: "媒体查询响应式布局",click: 89,price: 12},{title: "FLEX 弹性盒模型",click: 45,price: 120},{title: "GRID 栅格系统",click: 19,price: 67},{title: "盒子模型详解",click: 29,price: 300}];function order(field, type = "asc") {return function(a, b) {if (type == "asc") return a[field] > b[field] ? 1 : -1;//可以自由更改升序降序return a[field] > b[field] ? -1 : 1;//并且改变根据click/price的排序};}let hd = lessons.sort(order("price"));console.table(hd);

闭包导致的内存泄漏

获取一整个对象会很臃肿,当你只想获取一个对象里的属性,可以使用一种过河拆桥的方法:获取整个对象->使用属性->销毁对象,还可解决闭包导致的内存泄漏

不是foreach是同步,先执行foreach里的同步,item是空也是同步,元素的事件绑定是异步的:

let divs = document.querySelectorAll("div");divs.forEach(function (item) {let desc = item.getAttribute("desc");item.addEventListener("click", function () {// console.log(item.getAttribute("desc"));console.log(desc);//获取属性console.log(item);});item = null;//销毁对象});

this在闭包中的历史遗留问题

this在闭包里指向混乱:

 let hd = {user: "后盾人",get: function () {return function(){return this.user;}}};let a = hd.get();console.log(a())//undefined

这是个闭包结构,a是get方法,a()就是执行get方法,返回get方法里面的匿名函数的this.user,但是这个匿名函数是个函数啊,他的this是window,window里没有user这个属性,所以返回undefined

怎么让内部的匿名函数的this指向hd?声明一个this

let hd = {user: "后盾人",get: function () {let This=thisreturn function(){return This.user;}}};let a = hd.get();console.log(a())//后盾人

也可以用箭头函数,箭头函数的this指向get方法的this,也就是对象hd,这样就可以访问user了:

 let hd = {user: "后盾人",get: function() {return () => {return this.user;};}};let a = hd.get();console.log(a())//后盾人

后盾人老师我恨你。。。

相关文章:

想品客老师的第七天:闭包和作用域

闭包之前的内容写在这里 环境、作用域、回收 首先还是数据的回收问题&#xff0c;全局变量一般都是通过关闭页面回收的&#xff1b;而局部变量的值不用了&#xff0c;会被自动回收掉 像这种写在全局里的就不会被主动回收捏&#xff1a; let title 荷叶饭function fn() {ale…...

Web 代理、爬行器和爬虫

目录 Web 在线网页代理服务器的使用方法Web 在线网页代理服务器使用流程详解注意事项 Web 请求和响应中的代理方式Web 开发中的请求方法借助代理进行文件下载的示例 Web 服务器请求代理方式代理、网关和隧道的概念参考文献说明 爬虫的工作原理及案例网络爬虫概述爬虫工作原理 W…...

速通Docker === Docker 镜像分层存储机制

目录 分层存储的概念 分层存储的实现 镜像层 容器层 分层存储的优势 1. 镜像轻量化 2. 快速构建与部署 3. 高效的镜像共享 4. 版本控制 分层存储的示例 容器层的临时性与数据持久化 总结 Docker 的分层存储机制是其核心特性之一&#xff0c;它使得镜像的构建、共享和…...

开源智慧园区管理系统对比五款主流产品探索智能运营新模式

内容概要 在这个数字化迅速发展的时代&#xff0c;园区管理也迎来了全新的机遇和挑战。众所周知&#xff0c;开源智慧园区管理系统作为一种创新解决方案&#xff0c;正逐步打破传统管理的局限性。它的开放性不仅使得系统可以根据具体需求进行灵活调整&#xff0c;也为用户提供…...

用Devc++与easyx一步一步做游戏[启动界面部分]-解决hover闪烁问题及优化

在之前的博文中《用Devc与easyx一步一步做游戏[启动界面部分]-之按钮制作》&#xff0c;我们利用Devc和easyx完成了游戏启动界面按钮的基本制作&#xff0c;实现了按钮的绘制以及鼠标悬停时的信息提示功能。然而&#xff0c;目前还存在一个问题&#xff0c;即鼠标移动时&#x…...

非根目录部署 nextjs 项目,资源文件 请求404 的问题

最近在学习next项目编写的代码放到服务器上静态资源404 先分析问题 到服务器上查看是有资源目录的是不是项目配置有问题是不是nginx配置有问题 经过排查1和2是没有问题的目前来看只有3 检查一下nginx配置 尝试着把静态资源的配置禁用 问题解决 我的next项目用的是pm2管理…...

Kafka常见问题之 `javax.management.InstanceAlreadyExistsException`

文章目录 Kafka常见问题之 javax.management.InstanceAlreadyExistsException1. 概述2. 常见原因3. 具体异常示例4. 解决方案4.1 确保单一 Kafka Producer 实例4.2 配置 Kafka Broker 和 Producer 使用唯一的 JMX 名称&#xff08;对于Producer重点检查 client.id&#xff09;4…...

mysql 学习5 mysql图形化界面DataGrip下载 安装 使用

一、下载和安装 下载&#xff1a; 其他版本 - DataGrip PS&#xff1a;安装目录最好不要有中文。 C:\Program Files\JetBrains\DataGrip 2023.3.4 二、 夸克网盘分享 当前电脑是下载到 &#xff1a;D:\Ctool\mysql\datagrip2023_3_4\datagrip2024\jetbra-datagrip\scripts …...

读写和解析简单的 nc 文件

NetCDF 文件格式在气象数据工程领域占据着举足轻重的地位&#xff0c;其结构灵活、强兼容性等优势使其成为该领域的一个标准。无论是从事学术研究还是工程实践&#xff0c;掌握这种数据格式变得越发重要。其次&#xff0c;我注意到目前社区中气象编程大多数课程都聚焦于某个特定…...

LLM:BERT or BART 之BERT

文章目录 前言一、BERT1. Decoder-only2. Encoder-only3. Use of Bidirectional Context4. Masked Language Model (MLM)5. Next Sentence Prediction (NSP)6. Fine-tune1、情感分析2、句对分析3、命名实体识别&#xff08;NER&#xff09; 7. BERT总结 总结 前言 NLP选手对这…...

【力扣:新动计划,编程入门 —— 题解 ③】

—— 25.1.26 231. 2 的幂 给你一个整数 n&#xff0c;请你判断该整数是否是 2 的幂次方。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 如果存在一个整数 x 使得 n 2x &#xff0c;则认为 n 是 2 的幂次方。 示例 1&#xff1a; 输入&#xff1a;…...

数据库基础:从概念到 MySQL 实战

数据库基础&#xff1a;从概念到 MySQL 实战 在当今数字化时代&#xff0c;数据的重要性不言而喻&#xff0c;而数据库作为数据管理的核心工具&#xff0c;发挥着关键作用。对于技术爱好者和开发者来说&#xff0c;深入了解数据库知识是必不可少的。今天&#xff0c;就让我们一…...

Nacos统一配置管理

Nacos 统一配置管理 将一部分配置信息写到Nacos配置文件中&#xff0c;可以统一管理&#xff0c;并且这个文件支持热加载。 新建配置步骤&#xff1a;配置管理 -> 配置列表 -> 新建配置 Data ID&#xff08;配置文件名id&#xff09; 命名规范&#xff1a;服务名称-de…...

Centos7系统php8编译安装ImageMagick/Imagick扩展教程整理

Centos7系统php8编译安装ImageMagick/Imagick扩展教程整理 安装php8安装ImageMagick1、下载ImageMagick2、解压并安装3、查看是否安装成功 安装imagick扩展包 安装php8 点我安装php8 安装ImageMagick 1、下载ImageMagick wget https://www.imagemagick.org/download/ImageMa…...

android的gradle

Gradle User Manual gradle官网 这里有个gradlew很有用&#xff0c;因为这个可以在窗口中运行gradlew脚本 gradlew 和 gradlew.bat 都是 Gradle Wrapper&#xff08;Gradle 包装器&#xff09; 的一部分&#xff0c;它们的作用是让项目可以使用 Gradle 而无需提前在系统中…...

2025美赛MCM数学建模A题:《石头台阶的“记忆”:如何用数学揭开历史的足迹》(全网最全思路+模型)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ 《石头台阶的“记忆”&#xff1a;如何用数学揭开历史的足迹》 目录 《石头台阶的“记忆”&#xff1a;如何用数学揭开历史的足迹》 ✨摘要✨ ✨引言✨ 1. 引言的结构 2. 撰写步骤 &#xff08;1&#xff09;研究背景 &#…...

Python3 【高阶函数】项目实战:5 个学习案例

Python3 【高阶函数】项目实战&#xff1a;5 个学习案例 本文包含 5 个关于“高阶函数”的综合应用项目&#xff0c;每个项目都包含完整的程序代码、测试案例和执行结果。具体项目是&#xff1a; 成绩统计分析单词统计工具简易计算器工厂任务调度器数据管道处理 项目 1&#…...

ES6 类语法:JavaScript 的现代化面向对象编程

Hi&#xff0c;我是布兰妮甜 &#xff01;ECMAScript 2015&#xff0c;通常被称为 ES6 或 ES2015&#xff0c;是 JavaScript 语言的一次重大更新。它引入了许多新特性&#xff0c;其中最引人注目的就是类&#xff08;class&#xff09;语法。尽管 JavaScript 一直以来都支持基于…...

【S32K3 RTD LLD篇7】K344中心对齐PWM中心点触发ADC BCTU采样

【S32K3 RTD LLD篇7】K344中心对齐PWM中心点触发ADC BCTU采样 一&#xff0c;文档简介二&#xff0c;中心对齐PWM中心点触发ADC原理2.1 如何生成中心对齐的PWM2.2 如何生成PWM中心点触发标志 三&#xff0c; 软件配置与实现3.1 Demo CT 模块配置3.1.1 引脚配置3.1.2 时钟配置3.…...

解决日志中 `NOT NULL constraint failed` 异常的完整指南

在开发和运维过程中,日志是我们排查问题的重要工具。然而,当日志中出现类似 NOT NULL constraint failed 的异常时,往往意味着数据库约束与代码逻辑不匹配。本文将详细分析此类问题的原因,并提供完整的解决方案。 © ivwdcwso (ID: u012172506) 问题描述 在同步 AWS …...

14-6-3C++STL的list

&#xff08;一&#xff09;list的插入 1.list.insert(pos,elem);//在pos位置插入一个elem元素的拷贝&#xff0c;返回新数据的位置 #include <iostream> #include <list> using namespace std; int main() { list<int> lst; lst.push_back(10); l…...

协助工具-任意门导航

任意门导航网址&#xff1a;随意门导航-最全的实用导航网站,好用简洁宝藏网址神器...

优化使用 Flask 构建视频转 GIF 工具

优化使用 Flask 构建视频转 GIF 工具 优化后的项目概述 在优化后的版本中&#xff0c;我们将实现以下功能&#xff1a; 可设置每个 GIF 的帧率和大小&#xff1a;用户可以选择 GIF 的帧率和输出大小。改进的用户界面&#xff1a;使用更现代的设计使界面更美观、整洁。自定义…...

unity学习20:time相关基础 Time.time 和 Time.deltaTime

目录 1 unity里的几种基本时间 1.1 time 相关测试脚本 1.2 游戏开始到现在所用的时间 Time.time 1.3 时间缩放值 Time.timeScale 1.4 固定时间间隔 Time.fixedDeltaTime 1.5 两次响应时间之间的间隔&#xff1a;Time.deltaTime 1.6 对应测试代码 1.7 需要关注的2个基本…...

【趋势】《2024—2026金融科技十大趋势预测》一览

本白皮书基于新华三在金融行业的前沿实践和IDC的全球研究成果,深入分析了金融科技领域的十大关键趋势,旨在为金融机构提供前瞻性的战略指导和业务创新的参考。 导言 当前,在地缘政治冲突加剧、商业经济市场环境高度不确定、数字化业务加速发展的背景下,金融行业处于深度变…...

Qt调用ffmpeg库录屏并进行UDP组播推流

基于以下参考链接&#xff0c;采用其界面和程序框架&#xff0c;实现实时推送UDP组播视频流&#xff0c;替换原拉流功能 https://blog.csdn.net/u012532263/article/details/102736700 源码在windows&#xff08;qt-opensource-windows-x86-5.12.9.exe&#xff09;、ubuntu20.…...

HarmonyOS:创建应用静态快捷方式

一、前言 静态快捷方式是一种在系统中创建的可以快速访问应用程序或特定功能的链接。它通常可以在长按应用图标&#xff0c;以图标和相应的文字出现在应用图标的上方&#xff0c;用户可以迅速启动对应应用程序的组件。使用快捷方式&#xff0c;可以提高效率&#xff0c;节省了查…...

mysql 学习6 DQL语句,对数据库中的表进行 查询 操作

前期准备数据 重新create 一张表 create table emp(id int comment 编号,workno varchar(10) comment 工号,name varchar(10) comment 姓名,gender char comment 性别,ager tinyint unsigned comment 年龄,idcard char(18) comment 身份证号,workaddress varchar(10) c…...

【ES实战】治理项之索引模板相关治理

索引模板治理 文章目录 索引模板治理问题现象分析思路操作步骤问题程序化方案索引与索引模板增加分片数校验管理 彩蛋如何查询Flink on Yarn 模式下的Task Manager日志相关配置查询已停止的Flink任务查询未停止的Flink任务 问题现象 在集群索引新建时&#xff0c;索引的分片比…...

springboot3 集成 knife4j(接口文档)

提示&#xff1a;文章是集成 knife4j&#xff0c;而非 swagger2 或者 swagger3&#xff0c;效果如图 文章目录 前言一、添加依赖二、如何集成1.配置文件2.注解部分1.Tag2.Operation3.Parameter4.Schema 3.使用 总结 前言 提示&#xff1a;&#xff1a;大家在开发阶段&#xff…...