【JS】理解闭包及其应用

历史小剧场

明朝灭亡,并非是简单的政治问题,事实上,这是世界经济史上的一个重要案例。

所谓没钱,就是没有白银。----《明朝那些事儿》

什么是闭包?

闭包就是指有权访问另一个函数作用域中变量的函数

闭包变量存储位置?

  • 堆内存

假如闭包中的变量存储在栈内存中,那么栈的回收,会把处于栈顶的变量自动回收。所以闭包中的变量如果处于栈中那么变量被销毁后,闭包中的变量就没有了。所以闭包中的变量是处于堆内存中的。

闭包的作用?

  • 创造私有变量,且延长私有变量的生命周期

应用

  1. 延伸函数生命周期
js 复制代码
function hd() {
    let n = 1;
    return function sum() {
       console.log(++n)
    }
    sum()
}
let a = hd();
a(); // 2
a(); // 3
a(); // 4
a(); // 5
a(); // 6
let b = hd()
b() // 2
b() //3
let c = hd()
c() // 2

console.log("---------- 用完就删 --------")
function hd2() {
    let n = 1;
    function sum() {
       console.log(++n)
    }
    sum()
}
hd2()   // 2
hd2()   // 2
hd2()   // 2


console.log("-------------------------------")
const hd3 = () => {
    let n = 1;
    return () => {
        const m = () => console.log(++n)
        m()
    }
}
hd3()() // 2
hd3()() // 2


console.log("-------------------------------")
const hd4 = () => {
    let n = 1;
    return () => {
        return () => console.log(++n)
    }
}
const h4 = hd4()()
h4();   // 2
h4();   // 3
h4();   // 4
  1. var/let 在for循环中的执行原理
js 复制代码
for (var i = 1; i <= 3; i++) {
    console.log(`for里面:${i}`)
}
console.log(`for外面:${i}`) // 4


for (let j = 1; j <= 3; j++) {
    console.log(`for里面: ${j}`)
}
// console.log(`for外面: ${j}`) // ReferenceError: j is not defined


console.log("------------------------------")
for (var k = 1; k <= 3; k++) {
    setTimeout(() => {
        console.log(`var timeout for里面: ${k}`)    // 4 4 4
    }, 1000)
}

console.log("-------------------------------")
for (let l = 1; l <= 3; l++) {
    setTimeout(() => {
        console.log(`let timeout for里面: ${l}`)    // 1 2 3
    }, 1000)
}
  1. 多层作用域嵌套
js 复制代码
let arr1 = [];
for (let i = 1; i <= 3; i++) {
    arr1.push(() => i)
}
console.log(arr1[0]()); // 1
console.log(arr1[1]()); // 2
console.log(arr1[2]()); // 3


console.log("----------------------")
let arr2 = [];
for (var i = 1; i <= 3; i++) {
    arr2.push(() => i)
}
console.log(arr2[0]()) // 4
console.log(arr2[1]()) // 4
console.log(arr2[2]()) // 4

console.log("------------------")
let arr3 = [];
for (var i = 1; i <= 3; i++) {
    ((i) => arr3.push(() => i))(i)
}
console.log(arr3[0]()) // 1
console.log(arr3[1]()) // 2
console.log(arr3[2]()) // 3
  1. 获取商品区间以及商品排序

商品区间

js 复制代码
const goods = [
    {
        title: "A",
        price: 30,
    },
    {
        title: "B",
        price: 10,
    },
    {
        title: "C",
        price: 50,
    },
    {
        title: "D",
        price: 20,
    },
    {
        title: "E",
        price: 40,
    },
    {
        title: "F",
        price: 60,
    },
    {
        title: "G",
        price: 300,
    },
    {
        title: "H",
        price: 80,
    },
    {
        title: "I",
        price: 20,
    },
    {
        title: "J",
        price: 200
    }
]
console.log("---------------- 商品区间 -----------------")
const getPriceRange = (begin, end) => (val) => val.price >= begin && val.price <= end;
console.table(goods.filter(getPriceRange(20, 50))); // [ { title: 'B', price: 10 }, { title: 'D', price: 20 }, { title: 'E', price: 40 }, { title: 'F', price: 60 }, { title: 'I', price: 20 } ]
console.table(goods.filter(getPriceRange(40, 200))); 

运行结果:

商品排序

js 复制代码
const sortGoods = (key, order = "asc") => (a, b) => order === "asc"? a[key] - b[key] : b[key] - a[key];
console.table(goods.sort(sortGoods("price"))); // [ { title: 'B', price: 10 }, { title: 'D', price: 20 }, { title: 'E', price: 40 }, { title: 'F', price: 60 }, { title: 'I', price: 20 }, { title: 'A', price: 30 }, { title: 'C', price: 50 }, { title: 'H', price: 80 }, { title: 'J', price: 200 }, { title: 'G', price: 300 } ]
console.table(goods.sort(sortGoods("price", "desc"))); 

运行结果:

  1. 移动动画的闭包使用
js 复制代码
<!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>
        body {
            position: relative;
        }
        button {
            position: absolute;
        }
    </style>
</head>
<body>
    <!-- <button>你好</button> -->
    <button>真好</button>
    <script>
        const btns = document.querySelectorAll('button');
        // btns.forEach((btn) => {
        //     // parent
        //     let left = 1;
        //     btn.addEventListener('click', () => {
        //         setInterval(() => {
        //             console.log(left)
        //             btn.style.left = `${left++}px`;
        //         }, 100) // 会抖动
        //     })
        // })

        btns.forEach(btn => {
            let bind = false;
            btn.addEventListener('click', () => {
                if (!bind) {
                    let left = 1;
                    bind = setInterval(() => {
                        console.log(left)
                        btn.style.left = `${left++}px`;
                    }, 100)  // 不会抖动
                }
            })
        })
    </script>
</body>
</html>
  1. 实现缓存模拟localStorage
  • 可以通过set方法存值,get方法取值
js 复制代码
const myStorage = (function () {
    const cache = {}
    return {
        set: (key, val) => {
            cache[key] = val
        },
        get: (key) => {
            if (Object.prototype.hasOwnProperty.call(cache, key)) {
                return cache[key]
            }
        }
    }
})()

myStorage.set('name', 'Tom')
myStorage.set('age', 20)
console.log(myStorage.get('name')) //   Tom
console.log(myStorage.get('age')) //   20
相关推荐
金灰几秒前
HTML5--裸体回顾
java·开发语言·前端·javascript·html·html5
茶卡盐佑星_3 分钟前
说说你对es6中promise的理解?
前端·ecmascript·es6
爱上语文4 分钟前
Java LeetCode每日一题
java·开发语言·leetcode
Манго нектар31 分钟前
JavaScript for循环语句
开发语言·前端·javascript
蒲公英100138 分钟前
vue3学习:axios输入城市名称查询该城市天气
前端·vue.js·学习
程序猿小D40 分钟前
第二百六十九节 JPA教程 - JPA查询OrderBy两个属性示例
java·开发语言·数据库·windows·jpa
阿华的代码王国1 小时前
【JavaEE】——文件IO的应用
开发语言·python
satan–01 小时前
R语言的下载、安装及环境配置(Rstudio&VSCode)
开发语言·windows·vscode·r语言
天涯学馆1 小时前
Deno与Secure TypeScript:安全的后端开发
前端·typescript·deno
以对_1 小时前
uview表单校验不生效问题
前端·uni-app