说一说JavaScript 的closure 和 hoisting

本文深入讲解JavaScript中的闭包概念,包括闭包如何捕获外部作用域的变量、实现私有变量的方法、即时执行函数表达式(IIFE)的作用及变量提升(Hoisting)等核心知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

闭包(closure)

当声明一个函数时,其内部的变量的声明也在它的scope中被截获。比如下面的代码中,变量 x 绑定到了外部scope的值,然后对 x 的引用在bar的上下文中被截获。

var x = 4; // declaration in outer scope

function bar() {
    console.log(x); // outer scope is captured on declaration
}

bar(); // prints 4 to console
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

“截获”的概念很有意思,因为我们可以从外层scope使用和修改变量,甚至外层scope已经不存在了,比如:

function foo() {
    var x = 4; // declaration in outer scope

    function bar() {
        console.log(x); // outer scope is captured on declaration
    }

    return bar;

    // x goes out of scope after foo returns
}

var barWithX = foo();
barWithX(); // we can still access x
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

上面的例子中,当foo() 被调用时,其上下文在函数 bar() 中被截获。所以在它返回之后, bar() 仍然可以访问和修改变量 x。函数 foo(),其上下文在另一个函数中被截获,叫做闭包。

  • 私有数据 
    让我们做一些有意思的事,比如定义private变量,让它只对特定的函数可见:
function makeCounter() {
    var counter = 0;

    return {
        value: function () {
            return counter;
        },
        increment: function () {
            counter++;
        }
    };
}

var a = makeCounter();
var b = makeCounter();

a.increment();

console.log(a.value());
console.log(b.value());
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

输出

1
0
 
  • 1
  • 2
  • 1
  • 2

当 makeCounter() 被调用时,这个函数的快照会被保存。所有其内部的代码在执行过程中都使用这份快照。两次调用创建两个不同的快照,每个快照都有自己的counter变量。

  • IIFE 
    闭包也用于防止全局全名空间的污染,通常通过IIFE做到这一点。 
    IIFE是特殊的闭包,在声明之后立即调用。 
    假设我们想用 “$” 引用 jQuery,考虑下面的方法,不用IIFE。
var $ = jQuery;
// we've just polluted the global namespace by assigning window.$ to jQuery
 
  • 1
  • 2
  • 1
  • 2

下面的例子中,IIFE用于确保 “$” 绑定到了闭包创建的 jQuery

(function ($) {
    // $ is assigned to jQuery here
})(jQuery);
// but window.$ binding doesn't exist, so no pollution
 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

Hoisting

Hoisting是这样一个机制,把所有变量和函数的声明移动到它们的scope的顶部,但是,赋值仍然发生在声明的地方。比如:

    console.log(foo);
    // - > undefined
    var foo = 42;
    console.log(foo);
    // - > 42

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

上面的代码相当于:

    var foo; // Hoisted variable declaration
    console.log(foo);
    // - > undefined
    foo = 42; // variable assignment remains in the same place
    console.log(foo);
    // - > 42

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意因为上面的undefined 与运行下面代码得到的 not defined 不同:

    console.log(foo);
    // - > foo is not defined 
 
  • 1
  • 2
  • 1
  • 2

类似的理念也适用于函数。当函数被赋值给一个变量时,变量的声明就被hoisted了,而赋值还发生在原处。下面的两块代码是一样的:

    console.log(foo(2, 3));
    // - > foo is not a function
    var foo = function(a, b) {
        return a * b;
    }

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
    var foo;
    console.log(foo(2, 3));
    // - > foo is not a function
    foo = function(a, b) {
        return a * b;
    }

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

当声明function statements时,是不同的场景,不像function statements,函数的声明在它自己的scope内被hoisted,看下面的代码:

    console.log(foo(2, 3));
    // - > 6
    function foo(a, b) {
        return a * b;
    }

http://blog.eastmoney.com/j1550024695909052/blog_569728623.html

http://blog.eastmoney.com/j1550024695909052/blog_569766180.html

http://blog.eastmoney.com/j1550024695909052/blog_569918586.html

http://blog.eastmoney.com/j1550024695909052/blog_569921013.html

http://www.wang1314.com/doc/topic-1456493-1.html

http://www.wang1314.com/doc/topic-1456498-1.html

http://www.wang1314.com/doc/topic-1457924-1.html

http://www.wang1314.com/doc/topic-1457957-1.html

http://www.wang1314.com/doc/topic-1458112-1.html

http://guba.com/show-3718593-1.html

http://guba.com/show-3718597-1.html

http://guba.com/show-3719027-1.html

http://guba.com/show-3719030-1.html

http://guba.com/show-3719357-1.html

http://guba.com/show-3719362-1.html

http://guba.com/show-3719383-1.html

http://bbs.clzg.cn/thread-7527403-1-1.html

http://bbs.clzg.cn/thread-7527405-1-1.html

http://bbs.clzg.cn/thread-7530559-1-1.html

http://bbs.clzg.cn/thread-7530561-1-1.html

http://www.xici.net/d235738373.htm

http://www.xici.net/d235738497.htm

http://bbs.ttx.cn/read-htm-tid-8265379.html

http://bbs.ttx.cn/read-htm-tid-8265382.html

http://bbs.ttx.cn/read-htm-tid-8266162.html

http://bbs.ttx.cn/read-htm-tid-8266164.html

http://bbs.ttx.cn/read-htm-tid-8266210.html

http://bbs.ttx.cn/read-htm-tid-8266211.html

http://bbs.cnool.net/cthread-106557658.html

http://www.818u.com/beijing/qihuo/a39758178.html

http://www.818u.com/beijing/qihuo/a39758237.html

http://www.818u.com/beijing/qihuo/a39775650.html

http://www.kejiqi.com/baoxiangongsi/14407356x.html

http://www.kejiqi.com/baoxiangongsi/14407442x.html

http://www.kejiqi.com/baoxiangongsi/14422484x.html

http://www.kejiqi.com/baoxiangongsi/14422581x.html

http://www.togv.net/tiyupeixun/j2ydb9haab9g92sasimf.htm

http://www.togv.net/tiyupeixun/x45yu5ayyu5g2hwzhtmi.htm

http://www.togv.net/tiyupeixun/sxsmpu6rsrs6focqa34g.htm

http://www.mqshw.com/thread-196363-1-1.html

http://www.mqshw.com/thread-196365-1-1.html

http://www.mqshw.com/thread-196540-1-1.html

http://www.mqshw.com/thread-196541-1-1.html

http://beijing.baixing.com/licaifuwu/a1066628270.html

http://beijing.baixing.com/licaifuwu/a1066628884.html

http://bbs.henan100.com/thread-1075263-1-1.html

http://bbs.henan100.com/thread-1075269-1-1.html

http://bbs.henan100.com/thread-1077677-1-1.html

http://bbs.henan100.com/thread-1077686-1-1.html

http://bbs.henan100.com/thread-1077962-1-1.html

http://bbs.henan100.com/thread-1077968-1-1.html

http://bbs.jrhot.com/forum.php?mod=viewthread&tid=1503958

http://bbs.jrhot.com/thread-1503965-1-1.html

http://bbs.jrhot.com/thread-1504564-1-1.html

http://bbs.jrhot.com/thread-1504974-1-1.html

http://bbs.jrhot.com/thread-1505084-1-1.html

http://www.siteloop.net/article/355563.html

http://www.siteloop.net/article/355564.html

http://www.230la.com/news/show-97175.html

http://www.230la.com/news/show-97175.html

http://www.lxwei.com/thread-111213-1-1.html

http://www.lxwei.com/thread-111215-1-1.html

http://www.lxwei.com/thread-111503-1-1.html

http://bbs.qz.xmfish.com/read-htm-tid-2607602-ds-1.html

http://bbs.qz.xmfish.com/read-htm-tid-2607603-ds-1.html

http://bbs.qz.xmfish.com/read-htm-tid-2607787-ds-1.html

http://bbs.qz.xmfish.com/read-htm-tid-2607789-ds-1.html

http://bbs.qz.xmfish.com/read-htm-tid-2607810-ds-1.html

http://cn.51tie.com/touzidanbaobaoxian/11013233x.html

http://cn.51tie.com/touzidanbaobaoxian/11013247x.html

http://cn.51tie.com/touzidanbaobaoxian/11018075x.html

http://beijing.jinti.com/licai/22226159.htm

http://beijing.jinti.com/licai/22226196.htm

http://beijing.jinti.com/licai/22234470.htm

http://tieba.baidu.com/p/4865117012

http://tieba.baidu.com/p/4865516685

http://www.fwol.cn/xinxishow.php?xid=4229642

http://www.mqshw.com/thread-195832-1-1.html

http://www.mqshw.com/thread-195833-1-1.html

http://mt.sohu.com/20161117/n473403009.shtml

http://mt.sohu.com/20161117/n473423557.shtml

http://mt.sohu.com/20161117/n473413319.shtml

http://mt.sohu.com/20161117/n473413222.shtml

http://mt.sohu.com/20161117/n473432477.shtml

http://www.siteloop.net/article/355445.html

http://www.siteloop.net/article/355446.html

http://www.230la.com/news/show-97142.html

http://www.lxwei.com/thread-110356-1-1.html

http://www.lxwei.com/thread-110357-1-1.html

http://www.cnxixian.com/gqinfo/details.asp?id=40008

http://www.cnxixian.com/gqinfo/details.asp?id=40009

http://bbs.qz.xmfish.com/read-htm-tid-2607268-ds-1.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值