IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 闭包的详解 -> 正文阅读

[JavaScript知识库]闭包的详解

一、什么是闭包

闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现;也就是说,闭包可以让你在一个内层函数中访问到其外层函数的作用域(也通常被称为是函数之间的沟通的桥梁)。

1.1 闭包的3个特性
  • 函数嵌套函数;
  • 函数内部可以引用函数外部的参数和变量;
  • 参数和变量不会被垃圾回收机制回收。
1.2 函数作为返回值

经典①

function fn() {
  let age = 19;
  return function() {
    return age;
  }
}
let f1 = fn();
console.log(f1());

fn() 的返回值是一个匿名函数,在fn()函数作用域内部,匿名函数可以获取fn()作用域下变量age的值,将这个值赋给全局作用域下的变量变量f1;实现了全局作用域下获取到局部变量中的变量的值。

经典②

function fn() {
  let n = 2;
  return function() {
    let m = 0;
    console.log(n ++);
    console.log(m ++);
  }
}

let f2 = fn();
f2();//2  0
f2();//3  0

一般情况下,在fn()函数执行完后,就应该连同它里面的变量一同被销毁。但在这个例子里,由于匿名函数内部仍引用着fn里的变量n,所以n无法被销毁,而变量m是每次别调用时新创建的,所以每次f2执行完后,它就把属于自己的变量连同自己一起销毁。n未被销毁,这也产生了内存消耗问题,会影响性能。

1.3定时器与闭包
for(var i = 0; i < 5; i ++) {
  setTimeout(function() {
    console.log(i + ' ');
  }, 100);
}
// 5 
// 5 
// 5 
// 5 
// 5 

由于js是单线程的,在执行for循环的时候定时器setTimeout被安排到任务队列中排队等待执行,而在等待过程中for循环就已经在执行,等到setTimeout可以执行时,for循环已经结束,i的值已经变成5,所以打印出来五个5。

解方式一:将var改成let,

for( let i = 0; i < 5; i ++) {
  setTimeout(function() {
    console.log(i + ' ');
  }, 100);
}
// 0
// 1 
// 2 
// 3 
// 4 

解方式二:

for(var i = 0; i < 5; i ++) {
  (function(i) {
    setTimeout(function() {
      console.log(i + ' ');
    }, 100);
  }(i));
}
// 0 
// 1 
// 2 
// 3 
// 4

引入闭包老保存变量i,将setTimeout放入立即执行函数中,将for循环中的循环值作为参数传递,100ms后同时打印出0~4。

解方式三:

for(var i = 0; i < 5; i ++) {
  (function (i) {
    setTimeout(function() {
      console.log(i + ' ');
    }, i * 100);
  }(i));
}
// 0 
// 1 
// 2 
// 3 
// 4 

在上面代码块中,同时开启5个定时器,i*100是为5个定时器分别设置了不同时间,同时启动,执行时间不同,每个定时器间隔时间都是100ms,也就实现了每隔100ms就执行一次打印的效果。

1.4闭包作为参数传递
var num = 10;
var fn1 = function(x) {
  if(x > num) {
    console.log(x);
  }
}

void function(fn2) {
  fn2(30);
}(fn1);//30

fn1作为参数传入立即执行函数中,在执行到fn2(30)时候,30作为参数传入fn1中,这时候if(x > num)中的num取得并不是立即执行函数中的num,而是取创建函数的作用域中的num这里函数创建的作用域是全局作用域下,所以num取的是全局作用域中的值10,即30>10,打印30。

1.5 闭包的作用、坏处及应用

作用:

  • 保护函数内部的变量安全,实现封装,防止变量流入其他环境发生命名冲突;
  • 在内存中维持一个变量,可以缓存(但消耗内存,影响网页性能);
  • 匿名自执行函数可以减少内存消耗。

坏处:

  • 被引用的私有吧变量不能被销毁,增加了内存消耗,造成内存泄漏——> 解决:使用完变量后手动为它赋值为null;
  • 闭包涉及跨域访问,会导致性能损失——>解决:通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响。

应用:

  • for循环中的保留i 的操作;
  • 防抖和节流;
  • 函数柯里化;
  • 设计模式中的单例模式。
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-19 07:54:08  更:2021-09-19 07:54:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 11:03:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码