理解Javascript闭包

一、什么是闭包

GC 垃圾回收

复制代码
通常情况下,函数被调用后,内部的变量 会自动回收,不用的变量 内存自动释放

特殊情况下,例函数里的变量 还会被 用到的就不会被回收   例: 3按钮 点击按钮 弹出 索引+1

1. 闭包的底层:栈

复制代码
计算机 每调用一次函数时,内存就会 在内存中开辟一块空间,这个空间叫栈
整个函数的所有局部变量都在这个栈中运行

栈的本质:函数执行时会分配空间,函数结束时会回收

闭包可以做到的是:函数执行完了,栈也不回收,这就叫闭包

2.把函数当作对象处理

复制代码
对于某些语言来说,例java,不能存在独立的方法,一定是寄存在某个对象上,不管是静态的动态的,而js不一样,js中有独立存在的函数,只要函数调用时,它就会创建一个对象出来,这个对象就包含函数的各种细节
js 复制代码
function show(){
    let a=12;
    document.onclick=function(){
            alert(a);
    }
}
// 总结:尽管 a 是局部变量,但它不会被回收,因为 document.onclick 还会用到它

二、闭包的优缺点

js 复制代码
闭包的好处:
  延展了函数的局部作用域 的生命周期
  正常情况下,一个函数被调用后,它的作用域 就会被销毁;
  但当有闭包的情况时,局部作用域暂时不会销毁

闭包的缺点:
    不能立即释放作用域,销毁局部作用域

三、产生闭包的几种情况

php 复制代码
闭包是一个函数,可以访问独立数据的函数,
在一个作用域中可以访问另一个作用域的变量或者函数(嵌套的函数 访问了它外部的变量!!! (也可以是函数)
访问的外部函数是匿名函数时,Closure: 没有名字的函数)

function fn() {   var n = 10;     return n; }
fn();  // 未发生闭包:

发生闭包:   函数作为返回值

1.实例:获取1-10的随机数

js 复制代码
// 获取1-10的随机数
function getRandom(){
    var random = parseInt(Math.random()*10) + 1;
    return function(){
            return random;
    }
}
var fn = getRandom();
console.log(fn());

2.实例:计算两个数的和

js 复制代码
// 计算两个数的和
function getSum(n){
    return function(m){
            return n + m;
    }
}
// 求 100 + m
var fn = getSum(100);
// 求 1000 + m
var fn1000 = getSum(1000);

console.log(fn(1)); // 101
console.log(fn1000(1)); // 1001

3.实例:点击ul下的li,打印li对应的索引值

js 复制代码
// 方式一:
var heros = document.getElementById('heros');
var list = heros.children;   // 获取ul下的所有li
for (var i = 0; i < list.length; i++) {
	var li = list[i];
	li.index = i;
	li.onclick = function () {    // 给 li 注册点击事件
		console.log(this.index);  // 输出当前li对应的索引
	}
}

// 方式二:闭包
var heros = document.getElementById('heros');
var list = heros.children;
for (var i = 0; i < list.length; i++) {
    var li = list[i];

    (function(i){
            li.onclick = function () {
            console.log(i);
            }
    })(i)
}
// 不是学会闭包就一定要使用闭包,因为闭包也会带来一些问题,例上述的案例,每次循环都要创建一个自调用function,并且这个函数内部会创建作用域,因为这个函数发生了闭包,所以这个作用域并没有立即被释放,降低了性能(因为使用闭包,它延展了作用域,没有立即释放作用域)

4.实例:当for循环遇到定时器

js 复制代码
console.log('start');
for(var i = 0; i < 3; i++) {
	setTimeout(function(){
	  console.log(i);
	},0)
}
console.log('over'); // 控制台输出结果:start over 3个3  因为for循环的时机和setTimeout的执行时机不一样,当执行setTimeout时,循环早已结束

// 解决 function 中 输出的值 为 0 1 2
console.log('start');
for(var i = 0; i < 3; i++) {
  (function(i){
    setTimeout(function(){
      console.log(i);
    },0)
  })(i)
}
console.log('over'); 

5.实例:点击相应按钮i,字体变化

js 复制代码
// 普通方式:
var btn01 = document.getElementById('btn01');
var btn03 = document.getElementById('btn02');
var btn03 = document.getElementById('btn03');
btn01.onclick = function(){ document.body.style.fontSize = '12px';}
btn02.onclick = function(){ document.body.style.fontSize = '14px';}
btn03.onclick = function(){ document.body.style.fontSize = '16px';}


// 闭包方式:
var btn01 = document.getElementById('btn01');
var btn03 = document.getElementById('btn02');
var btn03 = document.getElementById('btn03');

// 创建一个函数,设置body字体的大小
function makeFun(size){
  return function(){
    document.body.style.fontSize = size +'px';
} }

btn01.onclick = makeFun(12);
btn02.onclick = makeFun(14);
btn03.onclick = makeFun(16);

// 循环+闭包的方式:
<div id="box">
  <button size="12">按钮1</button>
  <button size="14">按钮2</button>
  <button size="16">按钮3</button>
</div>

// js:创建一个函数,设置body的字体大小
function makeFun(size) {
  return function () {
    document.body.style.fontSize = size + 'px';
  }
}
var box = document.getElementById('box');
var buttons = box.children;
for (var i = 0; i < buttons.length; i++) {
  var btn = buttons[i];
  // 获取标签的自定义属性
  var size = btn.getAttribute('size');
  btn.onclick = makeFun(size);
}

四、定时器是如何工作的?

javascript 复制代码
console.log('start');
setTimeout(function(){
	console.log('timeout');
},0)
console.log('over'); // 输出结果:start  over  timeout

// 函数的执行 概念:
// 1.执行栈:先执行 执行栈上的函数,再去执行 任务队列中的函数
// 2.任务队列:setTimeout( ) 是一个函数,其中 function 作为参数 会被放在任务队列
//   此时函数并没有执行,而是在队列中排队
//   注册事件的 处理函数 function 也是放在任务队列上
相关推荐
霍志杰1 小时前
iframe加载或者切换时候,短暂的白屏频闪问题解决
前端·javascript·chrome
李小白661 小时前
论坛系统(中-2)
前端
曼汐 .2 小时前
企业网站架构部署与优化-Nginx核心功能
前端·nginx·架构
YUNYINGXIA2 小时前
Python实现Web请求与响应
开发语言·前端·python
愛芳芳2 小时前
vue3+element-plus+pinia完整搭建好看简洁的管理后台
前端·javascript·vue.js
zy happy3 小时前
黑马点评前端Nginx启动失败问题解决记录
java·运维·前端·spring boot·nginx·spring
进取星辰3 小时前
34、React Server Actions深度解析
前端·react.js·前端框架
麻辣香蝈蝈3 小时前
【Vue3】一文学会动态路由和编程式路由的使用
开发语言·前端·javascript·vue.js
CarryBircks3 小时前
nvm版本管理下pnpm 安装失败问题解决
前端·vue.js
凌冰_3 小时前
CSS3过渡
前端·css·css3