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

闭包之前的内容写在这里

环境、作用域、回收

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

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

      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())//后盾人

后盾人老师我恨你。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/68223.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在IDEA社区版Service面板中管理springboot项目

1、开启service仪表盘 2、在service仪表盘中&#xff0c;添加启动类配置项&#xff0c;专业版是SpringBoot 、社区版是application。 3、控制台彩色日志输出 右键启动类配置项&#xff0c;添加虚拟机参数 -Dspring.output.ansi.enabledALWAYS

网盘资源查找工具---AI功能

01 软件介绍 这是一款融入了ai技术的网盘搜索神器&#xff0c;可以让你更快&#xff0c;更精准的找到自己需要的文件&#xff0c;不管你是找影视&#xff0c;音乐&#xff0c;还是找软件或者学习资料都可以&#xff0c;欢迎前来使用。 02 功能展示 该软件非常简洁&#xff…

【2025年数学建模美赛E题】(农业生态系统)完整解析+模型代码+论文

生态共生与数值模拟&#xff1a;生态系统模型的物种种群动态研究 摘要1Introduction1.1Problem Background1.2Restatement of the Problem1.3Our Work 2 Assumptions and Justifications3 Notations4 模型的建立与求解4.1 农业生态系统模型的建立与求解4.1.1 模型建立4.1.2求解…

FPGA 使用 CLOCK_LOW_FANOUT 约束

使用 CLOCK_LOW_FANOUT 约束 您可以使用 CLOCK_LOW_FANOUT 约束在单个时钟区域中包含时钟缓存负载。在由全局时钟缓存直接驱动的时钟网段 上对 CLOCK_LOW_FANOUT 进行设置&#xff0c;而且全局时钟缓存扇出必须低于 2000 个负载。 注释&#xff1a; 当与其他时钟约束配合…

蓝桥杯3518 三国游戏 | 排序

题目传送门 这题的思路很巧妙&#xff0c;需要算出每个事件给三国带来的净贡献&#xff08;即本国士兵量减其他两国士兵量&#xff09;并对其排序&#xff0c;根据贪心的原理累加贡献量直到累加结果不大于0。最后对三国的胜利的最大事件数排序取最值即可。 n int(input()) a …

【redis初阶】redis客户端

目录 一、基本介绍 二、认识RESP&#xff08;redis自定的应用层协议名称&#xff09; 三、访问github的技巧 四、安装redisplusplus 4.1 安装 hiredis** 4.2 下载 redis-plus-plus 源码 4.3 编译/安装 redis-plus-plus 五、编写运行helloworld 六、redis命令演示 6.1 通用命令的…

LLM - 大模型 ScallingLaws 的设计 100B 预训练方案(PLM) 教程(5)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/145356022 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 Scalin…

HttpClient学习

目录 一、概述 二、HttpClient依赖介绍 1.导入HttpClient4依赖 2.或者导入HttpClient5依赖 3.二者区别 三、HttpClient发送Get请求和Post请求测试 (一)通过HttpClient发送Get请求 (二)通过HttpClient发送Post请求 一、概述 HttpClient是 Apache 软件基金会提供的一…

开源先锋DeepSeek-V3 LLM 大语言模型本地调用,打造自己专属 AI 助手

DeepSeek-V3是一个强大的混合专家 (MoE) 语言模型&#xff0c;总共有 671B 个参数。为了实现高效的推理和经济高效的训练&#xff0c;DeepSeek-V3 采用了多头潜在注意力机制 (MLA) 和 DeepSeekMoE 架构&#xff0c;这些架构在 DeepSeek-V2 中得到了彻底的验证。此外&#xff0c…

喜报丨迪捷软件入选2025年浙江省“重点省专”

根据《浙江省经济和信息化厅 浙江省财政厅关于进一步支持专精特新中小企业高质量发展的通知》&#xff08;浙经信企业〔2024〕232号&#xff09;有关要求&#xff0c;经企业自主申报、地方推荐、材料初审以及专家评审等程序&#xff0c;浙江省经济和信息化厅发布了2025年浙江省…

Golang Gin系列-8:单元测试与调试技术

在本章中&#xff0c;我们将探讨如何为Gin应用程序编写单元测试&#xff0c;使用有效的调试技术&#xff0c;以及优化性能。这包括设置测试环境、为处理程序和中间件编写测试、使用日志记录、使用调试工具以及分析应用程序以提高性能。 为Gin应用程序编写单元测试 设置测试环境…

深度学习 Pytorch 单层神经网络

神经网络是模仿人类大脑结构所构建的算法&#xff0c;在人脑里&#xff0c;我们有轴突连接神经元&#xff0c;在算法中&#xff0c;我们用圆表示神经元&#xff0c;用线表示神经元之间的连接&#xff0c;数据从神经网络的左侧输入&#xff0c;让神经元处理之后&#xff0c;从右…

Arduino大师练成手册 --控制 OLED

要在 Arduino 上使用 U8glib 库控制带有 7 个引脚的 SPI OLED 显示屏&#xff0c;你可以按照以下步骤进行&#xff1a; 7pin OLED硬件连接 GND&#xff1a;连接到 Arduino 的 GND 引脚。 VCC&#xff1a;连接到 Arduino 的 5V 引脚。 D0&#xff08;或 SCK/CLK&#xff09;…

CVE-2024-23897-Jenkins任意文件读取漏洞复现

content Jenkins是什么CVE-2024-23897总结修复建议 Jenkins是什么 Jenkins是一人基于Java开发的、可扩展的持续集成引擎&#xff0c;用于持续、自动地构建/测试软件项目&#xff0c;可以监控一些定时执行的任务。 官网文档&#xff1a; Jenkins是一款开源 CI&CD 软件&…

Lua 环境的安装

1.安装Lua运行环境 本人采用的是在windows系统中使用cmd指令方式进行安装&#xff0c;安装指令如下&#xff1a; winget install "lua for windows" 也曾使用可执行程序安装过&#xff0c;但由于电脑是加密电脑&#xff0c;最后都已失败告终。使用此方式安装可以安…

基于微信小程序的网上订餐管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

【矩阵二分】力扣378. 有序矩阵中第 K 小的元素

给你一个 n x n 矩阵 matrix &#xff0c;其中每行和每列元素均按升序排序&#xff0c;找到矩阵中第 k 小的元素。 请注意&#xff0c;它是 排序后 的第 k 小元素&#xff0c;而不是第 k 个 不同 的元素。 你必须找到一个内存复杂度优于 O(n2) 的解决方案。 示例 1&#xff1…

基于微信小程序的助农扶贫系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

Linux Futex学习笔记

Futex 简介 概述&#xff1a; Futex(Fast Userspace Mutex)是linux的一种特有机制&#xff0c;设计目标是避免传统的线程同步原语&#xff08;如mutex、条件变量等&#xff09;在用户空间和内核空间之间频繁的上下文切换。Futex允许在用户空间处理锁定和等待的操作&#xff0…

小柯剧场训练营第一期音乐剧演员与第二期报名拉开帷幕!

在当下社会文化浪潮中&#xff0c;小柯剧场凭借其独特的培养模式和“先看戏后买票”的良心举措&#xff0c;已然成为艺术界的一股清流。1月12日&#xff0c;由“第一期免费训练营”优秀学员们所带来的新一代《稳稳的幸福》成功落幕&#xff0c;引起了社会的广泛关注。该活动不仅…