理解JavaScript的闭包

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

内容简介:理解闭包需要搞懂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的闭包》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Impractical Python Projects

Impractical Python Projects

Lee Vaughan / No Starch Press / 2018-11 / USD 29.95

Impractical Python Projects picks up where the complete beginner books leave off, expanding on existing concepts and introducing new tools that you’ll use every day. And to keep things interesting, ea......一起来看看 《Impractical Python Projects》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

MD5 加密
MD5 加密

MD5 加密工具

SHA 加密
SHA 加密

SHA 加密工具