理解JavaScript的闭包

栏目: JavaScript · 发布时间: 5年前

内容简介:理解闭包需要搞懂JS的作用域,我们知道原因:
  • 闭包真言
  • 理解闭包情景一:函数作为返回值
  • 理解闭包情景二:函数作为参数传递到其他函数中
  • 理解闭包情景三:循环和闭包
  • 实际开发中闭包的应用
  • 闭包优缺点

闭包真言

  • JavaScript中闭包无处不在,你只需要能够识别并拥抱它。
  • 当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时就产生了闭包。

理解闭包需要搞懂JS的作用域, 我另外一篇文章:理解JavaScript的作用域

理解闭包

闭包情景一:函数作为返回值

function foo() {
    var a = 2;

    function bar() {
        console.log(a);
    }

    return bar;
}

var baz = foo();

baz(); // 2
复制代码

我们知道 bar 函数里面的 a 变量在外面是访问不到的,但调用 baz 方法为什么仍然能输出 2 呢?

原因:

  • 首先,调用 foo 函数把 bar 方法函数作为返回值,且赋值了给 baz 变量。
  • 然后, baz 变量就存在了对 bar 函数的引用。
  • 最后,调用 baz 方法时, a 去它的父级作用域( foo 函数)查询得到该值,所以就输出了 a 值。

这就是闭包的作用之一:把函数作为返回值,外部的作用域可以能访问到函数作用域内部的变量。

闭包情景二:函数作为参数传递到其他函数中

function foo() {
    var a = 2;

    function baz() {
        console.log(a); // 2
    }

    bar(baz);
}

function bar(fn) {
    fn();
}

foo()
复制代码

函数作为参数传递到其他函数中的原理和函数作为返回值差不多:

  • foo 函数的 bar 方法把内部的 baz 方法传入外部的 bar 方法中。
  • 外部的 bar 方法调用了传入的 baz 方法, a 去它的父级作用域(foo函数)查询得到值,所以就输出了 a 值。

这就是闭包的作用之二:函数作为参数传递到其他函数中,外部函数作用域也可以访问到其他函数内部作用域的变量。

闭包情景三:循环和闭包

需求:

在循环里面添加一个定时器,想预期每秒打印一次对应的值,如按顺序输出 1,2,3,4,5

代码:

以下代码是不能完成预期结果,都输出 6,6,6,6,6 ,原因: i 都是同一个引用for循环最后的结果: 6

for (var i = 1; i <= 5; i++) {
    setTimeout(function timer() {
        console.log(i);
    }, i * 1000);
}
复制代码

改进方案1

  • i 当做参数传入一个立即执行函数中,立即执行函数每次迭代时都创建一个新的作用域。
  • 这时候 i 拥有了自己的函数内部作用域,保存到每个对应的 i 值 ,就能到达预期的输出 1, 2, 3, 4, 5 结果。
for (var i=1; i<=5; i++) {
    (function(j) {
        setTimeout( function timer() {
            console.log( j );
        }, j*1000 );
    })( i );
}
复制代码

改进方案2

方案1可知,使用ES6的 let 声明也有块级作用域。

for循环头部的let声明,每次迭代都会声明一次 i ,那么每个 i 就有了自己的作用域,也能达到预期输出结果。

for (let i = 1; i <= 5; i++) {
    setTimeout(function timer() {
        console.log(i);
    }, i * 1000);
}
复制代码

这就是闭包的作用之三:能让一个变量长期存储在内存中。

实际开发中闭包的应用

收敛权限

// 检测一个数字是否被使用过
function isFirstLoad() {
    var _list = []
    return function (id) {
        if(_list.indexOf(id) >= 0) {
            return false
            
        }else {
            _list.push(id)
            
            return true
        }
    }
}

// 使用
// 如果第一次使用该数字则返回true,反之返回false
var firstLoad = isFirstLoad()
firstLoad(10) // true
firstLoad(10) // false
firstLoad(20) // true
复制代码

创建10个标签,点击的时候弹出来对应的序号

// 创建10个<a>标签,点击的时候弹出来对应的序号
for (var i = 0; i < 10; i++) {
    (function (i) {
        var a = document.createElement('a')
        a.innerHTML = i + '<br>'
        
        a.addEventListener('click', function (e) {
            e.preventDefault()
            console.log(i)
        })
        document.body.appendChild(a)
    })(i)
}
复制代码

以上所述就是小编给大家介绍的《理解JavaScript的闭包》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

人工智能产品经理——AI时代PM修炼手册

人工智能产品经理——AI时代PM修炼手册

张竞宇 / 电子工业出版社 / 2018-6 / 59

随着人工智能热潮的兴起,企业对人工智能领域产品经理的人才需求也开始井喷,人工智能产品经理成为顺应时代潮流的重要人力资源。实际上,人工智能确实给现有的产品和服务带来了全方位的升级,这也给产品经理从业人员提出了更高的要求,是关注人工智能产品的产品经理们面临的一次关键转型考验。 《人工智能产品经理——AI时代PM修炼手册》从知识体系、能力模型、沟通技巧等方面帮助大家系统地梳理了人工智能产品经理所必......一起来看看 《人工智能产品经理——AI时代PM修炼手册》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

随机密码生成器
随机密码生成器

多种字符组合密码