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

闭包之前的内容写在这里

环境、作用域、回收

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

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

      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.rhkb.cn/news/7789.html

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

相关文章

写一个存储“网站”的网站前的分析

要创建一个能够存储自己网站内容的“网站”,通常意味着你希望有一个可以存储网站数据、文件、内容等信息的系统。为了实现这一目标,可以考虑构建一个内容管理系统(CMS),这个系统能够帮助你存储和管理网站上的内容。 图片仅供参考 以下是如何实现一个可以存储自己网站内容…

aws(学习笔记第二十六课) 使用AWS Elastic Beanstalk

aws(学习笔记第二十六课) 使用aws Elastic Beanstalk 学习内容&#xff1a; AWS Elastic Beanstalk整体架构AWS Elastic Beanstalk的hands onAWS Elastic Beanstalk部署node.js程序包练习使用AWS Elastic Beanstalk的ebcli 1. AWS Elastic Beanstalk整体架构 官方的guide AWS…

从0到1:C++ 开启游戏开发奇幻之旅(一)

目录 为什么选择 C 进行游戏开发 性能卓越 内存管理精细 跨平台兼容性强 搭建 C 游戏开发环境 集成开发环境&#xff08;IDE&#xff09; Visual Studio CLion 图形库 SDL&#xff08;Simple DirectMedia Layer&#xff09; SFML&#xff08;Simple and Fast Multim…

vim的多文件操作

[rootxxx ~]# vim aa.txt bb.txt cc.txt #多文件操作 next #下一个文件 prev #上一个文件 first #第一个文件 last #最后一个文件 快捷键: ctrlshift^ #当前和上个之间切换 说明&#xff1a;快捷键ctrlshift^&#xff0c…

安宝特方案 | AR在供应链管理中的应用:提升效率与透明度

随着全球化的不断深入和市场需求的快速变化&#xff0c;企业对供应链管理的要求也日益提高。如何在复杂的供应链环境中提升效率、降低成本&#xff0c;并确保信息的透明度&#xff0c;成为了各大行业亟待解决的问题。而增强现实&#xff08;AR&#xff09;技术&#xff0c;特别…

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

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

winfrom项目,引用EPPlus.dll实现将DataTable 中的数据保存到Excel文件

最近研究不安装office也可以保存Excel文件&#xff0c;在网上查询资料找到这个方法。 第一步&#xff1a;下载EPPlus.dll文件&#xff08;自行去网上搜索下载&#xff09; 第二步&#xff1a;引用到需要用的项目中&#xff0c;如图所示&#xff1a; 第三步&#xff1a;写代码…

Unity git版本管理

创建仓库的时候添加了Unity的.gitignore模版&#xff0c;在这个时候就能自动过滤不需要的文件 打开git bash之后&#xff0c;步骤git版本管理-CSDN博客 如果报错&#xff0c;尝试重新进git 第一次传会耗时较长&#xff0c;之后的更新就很快了

分布式微服务系统简述

distributed microservice 分布式与微服务的定义及关系&#xff1b;分布式微服务架构里的各组件&#xff0c;如&#xff1a;配置中心、服务注册/发现、服务网关、负载均衡器、限流降级、断路器、服务调用、分布式事务等&#xff1b;spring cloud 介绍及实现案例&#xff0c;如…

npm启动前端项目时报错(vue) error:0308010C:digital envelope routines::unsupported

vue 启动项目时&#xff0c;npm run serve 报下面的错&#xff1a; error:0308010C:digital envelope routines::unsupported at new Hash (node:internal/crypto/hash:67:19) at Object.createHash (node:crypto:133:10) at FSReqCallback.readFileAfterClose [as on…

国产编辑器EverEdit - 大纲视图

1 大纲视图 1.1 应用场景 在编辑较长代码文件时&#xff0c;使用大纲视图可以方便的检视当前文件的变量、函数等信息&#xff0c;方便在不同函数间跳转&#xff0c;对整个文档的全貌了然于胸。   在编辑XML文档时&#xff0c;通过展示XML文件的层次结构、节点布局&#xff0…

FastExcel的使用

前言 FastExcel 是一款基于 Java 的开源库&#xff0c;旨在提供快速、简洁且能解决大文件内存溢出问题的 Excel 处理工具。它兼容 EasyExcel&#xff0c;提供性能优化、bug 修复&#xff0c;并新增了如读取指定行数和将 Excel 转换为 PDF 的功能。 FastExcel 的主要功能 高性…

GESP2024年3月认证C++六级( 第三部分编程题(1)游戏)

参考程序&#xff1a; #include <cstdio> using namespace std; const int N 2e5 5; const int mod 1e9 7; int n, a, b, c; int f[N << 1]; int ans; int main() {scanf("%d%d%d%d", &n, &a, &b, &c);f[N n] 1;for (int i n; i…

JVM深入学习(一)

目录 一.JVM概述 1.1 为什么要学jvm&#xff1f; 1.2 jvm的作用 1.3 jvm内部构造 二.JVM类加载 2.1类加载过程 2.2类加载器 2.3类加载器的分类 2.4双亲委派机制 三.运行时数据区 堆空间区域划分&#xff08;堆&#xff09; 为什么分区(代)&#xff1f;&#xff08…

java后端之事务管理

Transactional注解&#xff1a;作用于业务层的方法、类、接口上&#xff0c;将当前方法交给spring进行事务管理&#xff0c;执行前开启事务&#xff0c;成功执行则提交事务&#xff0c;执行异常回滚事务 spring事务管理日志&#xff1a; 默认情况下&#xff0c;只有出现Runti…

hadoop==docker desktop搭建hadoop

hdfs map readuce yarn https://medium.com/guillermovc/setting-up-hadoop-with-docker-and-using-mapreduce-framework-c1cd125d4f7b 清理资源 docker-compose down docker system prune -f

类和对象(4)——多态:方法重写与动态绑定、向上转型和向下转型、多态的实现条件

目录 1. 向上转型和向下转型 1.1 向上转型 1.2 向下转型 1.3 instanceof关键字 2. 重写&#xff08;overidde&#xff09; 2.1 方法重写的规则 2.1.1 基础规则 2.1.2 深层规则 2.2 三种不能重写的方法 final修饰 private修饰 static修饰 3. 动态绑定 3.1 动态绑…

Java 实现Excel转HTML、或HTML转Excel

Excel是一种电子表格格式&#xff0c;广泛用于数据处理和分析&#xff0c;而HTM则是一种用于创建网页的标记语言。虽然两者在用途上存在差异&#xff0c;但有时我们需要将数据从一种格式转换为另一种格式&#xff0c;以便更好地利用和展示数据。本文将介绍如何通过 Java 实现 E…

嵌入式蓝桥杯电子赛嵌入式(第14届国赛真题)总结

打开systic 生成工程编译查看是否有问题同时打开对应需要的文档 修改名称的要求 5.简单浏览赛题 选择题&#xff0c;跟单片机有关的可以查相关手册 答题顺序 先从显示开始看 1,2 所以先打开PA1的定时器这次选TIM2 从模式、TI2FP2二通道、内部时钟、1通道设为直接2通道设置…

Oracle Agile PLM Web Service Java示例测试开发(一)环境环境、准备说明

1 说明 1.1 PLM信息介绍 PLM&#xff1a;Oracle的产品Agile PLM&#xff08;Agile Product Lifecycle Management&#xff09; 版本号&#xff1a;9.3.6 (Build 47) Path&#xff1a;https://IP:7002/Agile/default/login-cms.jsp 1.2 开发工具和环境说明 开发工具&#xf…