总结:闭包就一窗户纸


前提,要知道的


上面都懂了?
懂了为什么还不懂闭包?🐶

那下面不厌其烦再重复些重点。

懂了这些重点,自然就懂闭包了。



# 作用域

## 延伸函数环境生命周期

    <script>
        function hd() {
            let n = 1 ; 
            return function b() {
                let m = 1 ; 
                console.log("b n " , ++n);
                console.log("b m " , ++m);
                return function c() {
                    console.log("c n ",++n);
                    console.log("c m ",++m);
                }
            }
        }
        let a = hd() ; 
        console.log("-------------------------");
        a();
        console.log("-------------------------");
        a();
        console.log("-------------------------");
        a();
        console.log("-------------------------");
        console.log("-------------------------");
        let b = hd()(); 
        console.log("-------------------------");
        b();
        console.log("-------------------------");
        b();
        console.log("-------------------------");
        b();
        console.log("-------------------------");
    </script>

## 构造函数 作用域

  • https://editor.csdn.net/md/?articleId=104178267

## 块 作用域

{
    var a = 1 ; 
}
{
    const a = 2 ; 
}
console.log(window.a); 

## let const var 在 for 循环中 执行 原理

https://www.bilibili.com/video/av77016015?p=6

如何 , 用 var 做 for循环?

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

## 多级作用域嵌套

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

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


# 闭包

## 闭包获得区间商品

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 ; 
	} ; 
}

lessons.filter(between(10 , 100) );

## 闭包解决 线程问题

下面代码, 点多几次,出现抖动问题

<!DOCTYPE html>
<html lang="en">
<head>

    
    <title>Document</title>
    <style> button{ position: absolute; } </style>
</head>

<body>
    <button message="aaa" >abc</button> <br>
    <button message="bbb">bbb</button>
</body>
    <script> let btns = document.querySelectorAll('button'); btns.forEach(function(item) { item.addEventListener('click' , function() { let left = 1 ; setInterval(function() { item.style.left = left++ + "px" ; } , 100); }) ; }); </script>
</html>

闭包特性,把值放外面,可访问

<!DOCTYPE html>
<html lang="en">
<head>

    
    <title>Document</title>
    <style> button{ position: absolute; } </style>
</head>

<body>
    <button message="aaa" >abc</button> <br>
    <button message="bbb">bbb</button>
</body>
    <script> let btns = document.querySelectorAll('button'); btns.forEach(function(item) { let left = 1 ; item.addEventListener('click' , function() { setInterval(function() { item.style.left = left++ + "px" ; } , 100); }) ; }); </script>
</html>

不抖动,但是新问题:再次点击,加快

最终解决方法,设置一个开关。
setInterval 返回的是 定时器编号

<!DOCTYPE html>
<html lang="en">
<head>

    
    <title>Document</title>
    <style>
        button{
            position: absolute;
        }
    </style>
</head>

<body>
    <button message="aaa" >abc</button> <br>
    <button message="bbb">bbb</button>
</body>
    <script>
        let btns = document.querySelectorAll('button');
        btns.forEach(function(item) {
            let bind = false; 
            item.addEventListener('click' , function() {
                if(!bind) {
                    let left = 1 ; 
                    bind = setInterval(function() {
                        item.style.left =  left++ + "px" ; 
                    } , 5);
                    console.log(bind);
                }
            }) ;
        });
    </script>
</html>


## 闭包 排序 (种类、升降序)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script>
        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') { //asc 升序 desc 降序
            return function(a , b ) {
                let flag = a[field]>b[field] ; 
                if(type == 'asc') return  flag ? 1 : -1  ; 
                return flag ? -1 : 1 ; 
            } ; 
        } ; 
        let hd = lessons.sort(order('price'));
        console.table(hd) ; 
    </script>
</body>
</html>

# 闭包可能的问题

## 内存泄漏

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div desc='aaaa'>aaa</div>
    <div desc='bbbb'>bbb</div>
    <script>
        let divs = document.querySelectorAll('div') ;
        divs.forEach(function(item)  {
            let desc = item.getAttribute("desc");
            item.addEventListener('click' , function(){
                console.log(desc);
                console.log(item);
            }) ;
            item = null ;  // 不加上这个,导致内存泄漏
        });
    </script>
</body>
</html>