作用域闭包

芝麻凛 2021年11月10日 200次浏览
function foo(){
    var a = 2;
    function bar(){
        console.log(a);
    }
    return bar;
}
var baz = foo();
baz(); // 2 ---这就是闭包的效果

无论使用什么方式对函数类型的值进行传递,当函数在别处被调用时都可以观察到闭包。

function foo(){
    var a = 2;
    function baz(){
        console.log(a)
    }
    bar(baz);
}
function bar(fn){
    fn();
}
foo()

把内部函数baz传递给bar,当调用这个内部函数时(fn),它涵盖的foo()内部作用域的闭包就可以观察到了,因为它能够访问啊。

传递函数也可以是间接的。

var fn;
function foo(){
    var a = 2;
    function baz(){
        console.log(a);
    }
    fn = baz;//将baz分配给全局变量
}
function bar(){
    fn(); //这也是闭包
}
foo();

bar(); //2

无论通过何种手段将内部函数传递到所在的词法作用域之外,它都会持有对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包。

将一个内部函数timer传递给setTimeout(...)。timer具有涵盖wait(...)作用域的闭包,因此还保有对变量message的引用。
wait(...)执行1000毫秒之后,它的内部作用域并不会消失,timer函数依旧保有wait(...)作用域的闭包。
在引擎内部,内置的工具函数setTimeout()持有对一个参数的引用,这个参数也许叫做fn或func。引擎会调用这个函数,在下面例子中就是内部的timer函数,而词法作用域在这个过程中保持完整。
这就是闭包

function wait(message){
    setTimeout(function timer(){
        console.log(message)
    },1000)
}
wait("Hello, closure");
//jQuery理解闭包
function setupBot(name,selector){
    $(selector).click(function activator(){
	console.log("Activating: " + name)
    })
}

setupBot("Closure Bot 1", "#bot_1");
setupBot("Closure Bot 2", "#bot_2");

本质上无论何时何地,如果将(访问它们各自词法作用域的)函数当做第一级的值类型并到处传递,就会看到闭包在这些函数中的应用。
在定时器、事件监听器、Ajax请求、跨窗口通信或者任何异步/同步任务中,只要使用了回调函数,实际上就是在使用闭包!