JS-闭包

作者: 刘淘 | 来源:发表于2020-06-15 23:02 被阅读0次

0.闭包

理解闭包的关键在于:外部函数调用之后其变量对象本应该被销毁,但闭包的存在使得我们仍旧可以访问外部函数的变量。
闭包的特性:
1. 函数内再嵌套函数
2. 内部函数可以引用外层的参数和变量
3. 参数和变量不会被垃圾回收机制回收


使用闭包主要是为了设计私有的方法和变量。
闭包的优点是可以避免全局变量的污染,
缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。


在js中,函数即闭包,只有函数才会产生作用域的概念。


闭包用处:
一个是可以读取函数内部的变量,
另一个就是让这些变量始终保持在内存中
闭包的另一个用处,是封装对象的私有属性和私有方法


由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用 闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露

解决方法是,在退出函数之前,将不使用的局部变量全部删除

function outer() {
    var a = 1;
    return function() {
        return a;
    };
}
var b = outer();
console.log(b()); //1
  • 闭包即在多级函数嵌套环境下,内部函数可以调用外部函数成员的一种代码组织形式,但外部却无法访问内部成员。
  • 认识闭包,首先认识作用域概念,内外函数都有自身存在的作用域范围,以便各自成员被其他函数调用或访问。
  • 函数作用域中的常量,只对当前函数以及子函数有效,在作用域外部无法访问。
  • 每次函数调用都会重新开辟一块内存空间,存储当前函数成员。


    image.png

1.函数作用域

延长作用域的生命周期
之前提到过,每次函数调用读会开辟一块新的内存空间,产生一套新的运行环境,那如何才能保存上一次的运行结果呢?
当然可以,在主函数内部返回新函数,让新函数来保存主函数的运行结果。

//主函数
function sum() {
    let i = 1
    //新函数
    //主函数内部返回新函数(匿名),让新函数来保存主函数的运行的结果
    return function () { 
        //多次执行返回的新函数不会开辟新的内存空间 ,但主函数再次调用又产生一个新的函数,
        //此时新的函数读取的i 是从老内存中读取的,而老内存上一步中已经将i变成了2
        let j = 1
        function show() {
            ++i;
            ++j;
            console.log(`i:${i} j:${j}`)
        }
        show()
    }
}
const sum1 = sum()
sum1() //i:2 j:2
sum1() //i:3 j:2
//主函数
function sum2() {
    let x = 1
    //新函数
    //主函数内部返回新函数(匿名),让新函数来保存主函数的运行的结果
    return function () {
        let y = 1
        return function () { 
            //新函数保存主函数的运行结果,每次调用主函数将再次产生一个新函数
            //由于返回的新函数不被重新开辟内存空间,新函数读取到的x y 是上次操作过的值
            ++x;
            ++y;
            console.log(`x:${x} y:${y}`)
        }
    }
}
const sum2x = sum2()() //两个return函数 ,两个括号才可以获取到最终的函数
sum2x() //x:2 y:2
sum2x() //x:3 y:3

2.块级作用域

  • 块级作用域,类似函数作用域,let const是有块级作用域的,var没有块级作用域,var是全局作用域,挂载在window上
  • 每个块级作用域内的成员都彼此独立的,因此多个块作用域可定义同名成员
  • var 虽然没有块级作用域,但有函数作用域,因此也就能达到‘伪块级作用域’的效果
    在Java等其他语言中,当循环完毕,变量将被销毁,但是在js中
    在for循环外部,使用var定义的循环变量仍然有效


    image.png

    在for循环外部,使用let定义的循环变量无效。因为let有块级作用域,超出了块级作用域


    image.png
image.png

3.应用场景示例

闭包就是在多级函数嵌套下,内部函数可以调用外部函数成员的一种代码组织形式。

/**
 * 获取指定范围的数字
*/
var array = [1, 2, 3, 4, 5, 6]
//知道需要 首先想到数组的过滤filter方法,可以根据条件过滤
const filterData = array.filter(function (item) { return item > 2 && item < 6 })
console.log("=="+filterData)
//现在条件是写死的,我要怎么才能让条件 2 6 变成动态的呢? 
//这个时候就应该想到闭包,闭包:嵌套函数 内部函数可以访问外部函数的变量
function between(a, b) {
    return function (item) { 
        return item > 2 && item < 6  
        }
}
console.log("闭包真是秒呀秒呀"+array.filter(between(2,6)))
/**
 * 筛选出成绩在60-70之间的学生
*/
const students = [
    { name: 'a', score: 61, age: 10 },
    { name: 'b', score: 62, age: 19 },
    { name: 'c', score: 30, age: 20 },
    { name: 'd', score: 80, age: 22 },
    { name: 'e', score: 70, age: 22 },
    { name: 'f', score: 66, age: 11 },
]
students.filter(function (item) { return item.score > 60 && item.score < 70 });

const scoreRange = function scoreRange(a, b) {
    return function (item) {
        return item.score > a && item.score < b
    }
}
console.log(JSON.stringify(students.filter(scoreRange(60, 70))))

//现在问题来了 我突然想按照年龄 能不能更灵活一些呢?
const proertyRange = function scoreRange(a, b,property) {
    return function (item) {
        return item[property] > a && item[property] < b
    }
}
console.log("age:"+JSON.stringify(students.filter(proertyRange(18, 70,'age'))))

4.内存泄露

/**
*由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用 闭包,
*否则会造成网页的性能问题,在IE中可能导致内存泄露
*解决方法是,在退出函数之前,将不使用的局部变量全部删除
*
 */
const buttons = document.querySelectorAll('button')
buttons.forEach(function (item) {

    const name = item.getAttribute('name')

    item.addEventListener('click', function () {
        console.log(item.getAttribute('name'))
        console.log(name)
    })

    item = null // 解决内存泄露 ,在退出函数之前,将不使用的局部变量全部删除
})

相关文章

  • js-闭包

    对于闭包的理解,一直很浅懂,特别有时候跟匿名函数混淆。所以收集下面各路对于闭包的讲解。 维基百科中的解释:“在计算...

  • js-闭包

  • Js-闭包

    「闭包」 要理解什么闭包,首先要知道闭包为啥出现,实际代码中,我们想在某一的作用域中使用一个变量,很简单,直接在外...

  • js-闭包

    为什么写闭包: 1.被人说复杂,想整清晰.其实很好理解. 2.闭包在开发中用途很多.面试经常问,必须弄懂. 为什么...

  • JS-闭包

    一、闭包简介1、函数内部的函数可以生成闭包2、闭包的应用:需要多个内部变量值3、闭包弊端闭包:会倒致函数运行结束后...

  • js-闭包

    了解闭包前,先了解变量:局部变量和全局变量。 接下来的问题是,如何从外部获取局部变量: 如上,f5可以读取f4中的...

  • JS-闭包

    0.闭包 理解闭包的关键在于:外部函数调用之后其变量对象本应该被销毁,但闭包的存在使得我们仍旧可以访问外部函数的变...

  • js-闭包

    今天学习的概念是闭包一般的计数器需要借助全局变量 var counter = 0; //全局变量function ...

  • JS-闭包

    了解闭包前,首先要知道声明是变量作用域变量根据作用域的不同分为两种:全局变量和局部变量。1.函数内部可以使用全局变...

  • JS-读懂闭包

    长久以来,闭包是前端同学面试必考的问题。会用闭包也成了高级前端开发者的标志,今天就来彻底弄清楚闭包的每一个细节。 ...

网友评论

    本文标题:JS-闭包

    本文链接:https://www.haomeiwen.com/subject/onqqxktx.html