闭包及其运用

什么是闭包?

“在函数内运用别的函数内的变量,是为闭包”

【例1】
function a() {
    let num = 100;
    return function b() {
        console.log(num)
    }
}
var c = a()
c()   // 100

在例 1 中,a 为外层函数,a中返回了一个内部函数 b , 函数 b 中运用了 a 中的 num 变量。此时,函数 b 就形成了一个闭包。

闭包的用途是什么?

在JavaScript中,作用域链使得子作用域能够读取到父作用域的变量【见例2】,而反过来,父作用域没法直接猎取子作用域的变量【见例3】。

【例2】
let num = 100
function a() {
    console.log(num)
}
a()   // 100



【例3】
function a() {
    let num = 100
}
console.log(num)   // error: not defined

当我们想在父作用域运用子作用域的值时该怎么办呢?

答:那就在函数内部再定一个函数,将其作为返回值即可【例4】。

【例4】
function a() {
    let num = 100
    return function b() {
        return num
    }
}
var x = a()
console.log(x())   // 100

例 4 中,函数 b 作为函数 a 的内部函数,能够接见 a 中的变量 num,因而我们将函数 b 作为返回值,我们经由过程操纵 b 来接见 a 的变量。

上述运用闭包的特征来完成外部对内部的接见,就是闭包最基本的运用。

闭包的运用场景

1. 封装变量以掌握权限

一般来说,我们只想让外界运用我们暴露出去的要领,而要领涉及到的变量盘算想要封装在函数内部,以防止被故意/无意地修正变量值,此时,便可运用闭包来举行变量封装以掌握权限【例5】。

【例5】
// 推断输入的变量是不是是第一次输入
function isFirstVisit() {
    let _list = []
    return function (id) {
        if (_list.indexOf(id) >= 0) {
            console.log("Exist!")
        } else {
            _list.push(id)
            console.log("Added~")
        }
    }
}
let firstVisit = isFirstVisit()
firstVisit(5)   // Added~
firstVisit(5)   // Exist!
firstVisit(10)   // Added~

将 isFirstVisit 的返回值赋给 firstVisit ,然后经由过程运用 firstVisit 举行推断,因为暴露给外界运用的是 firstVisit 函数,所以只能运用该函数定义的要领,而没法对 _list 举行任何修正,保证了数据的私密性。

2. 函数柯里化

函数柯里化就是把一个函数吸收多个参数举行处置惩罚,转变为吸收单一参数,然后返回一个新函数吸收下一个参数【见例6】。

【例6】
// 一般函数
function sum(x, y) {
    return x + y
}
// 函数柯里化
function curryingSum(x) {
    return function(y) {
        return x + y
    }
}

这里函数柯里化后的内部函数所运用的 x,就是其父作用域的变量,此时的内部函数就是一个闭包。

函数柯里化运用之
参数复用

【例7】 
function check(reg, txt) {
    return reg.test(txt)
}

// 磨练是不是含有数字
check(/\d+/g, 'test')   // false
check(/\d+/g, 'abc')   // false
check(/\d+/g, '2dd')   // true

// 柯里化后
function curryingCheck(reg) {
    return function(txt) {
        return reg.test(txt)
    }
}

let hasNumber = curryingCheck(/\d+/g)

hasNumber('test')      // false
hasNumber('abc')   // false
hasNumber('2dd')   // true

经由过程上例能够看到,直接运用check函数,第一个参数“正则推断语句”在每次运用时都须要输入,既不雅观也不方便。对其举行函数柯里化后,只需输入一次正则推断语句,便可对推断函数举行复用。

闭包带来的题目

内存占用

因为闭包运用别的函数内的变量,所以渣滓接纳机制不会对闭包相干的函数举行接纳,占用内存空间。

    原文作者:bmwz110
    原文地址: https://segmentfault.com/a/1190000019349658
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞