作用域闭包《你不知道的JavaScript(上)》

Posted 依旧那片天

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了作用域闭包《你不知道的JavaScript(上)》相关的知识,希望对你有一定的参考价值。

当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是当前词法作用域之外执行。

 

function foo() {
    var a = 2;
    function bar() {
        console.log(a); // 2
    }
    bar();
}
foo();
function foo() {
    var a = 2;
    function bar() {
        console.log(a);
    }
    return bar;
}
var baz = foo();
baz(); // 2 朋友,这就是闭包的效果

bar()依然持有对该作用域的引用,而这个引用就叫做闭包。

 

这个函数在定义时的词法作用域以外的地方被调用。

闭包使得函数可以继续访问定义时的词法作用域

var fn;
function foo() {
    var a = 2;
    function baz() {
        console.log( a );
    }
     fn = baz; // 将 baz 分配给全局变量
}
function bar() {
    fn(); // 妈妈快看呀, 这就是闭包!
} 
foo();
bar(); // 2

 


 

function wait(message) {
    setTimeout( function timer() {
        console.log( message );
    }, 1000 );
} 
wait( "Hello, closure!" );

将一个内部函数(名为 timer) 传递给 setTimeout(..),timer 具有涵盖 wait(..) 作用域的闭包, 因此还保有对变量 message 的引用。

wait(..) 执行 1000 毫秒后, 它的内部作用域并不会消失, timer 函数依然保有 wait(..)作用域的闭包。 

 

只要使用了回调函数,实际上就是在使用闭包!

 


 

function CoolModule() {
    var something = "cool";
    var another = [1, 2, 3];
    function doSomething() {
        console.log( something );
    }
    function doAnother() {
        console.log( another.join( " ! " ) );
    }
    return {
        doSomething: doSomething,
        doAnother: doAnother
    };
}
var foo = CoolModule();
foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3

这个模式在 javascript 中被称为模块。 最常见的实现模块模式的方法通常被称为模块暴露,这里展示的是其变体。 

 

模块模式需要具备两个必要条件。

1. 必须有外部的封闭函数, 该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)。 

2. 封闭函数必须返回至少一个内部函数, 这样内部函数才能在私有作用域中形成闭包, 并 且可以访问或者修改私有的状态。 

 

当只需要一个实例时, 可以对这个模式进行简单的改进来实现单例模式:

var foo = (function CoolModule() {
    var something = "cool";
    var another = [1, 2, 3];
    function doSomething() {
        console.log( something );
    }
    function doAnother() {
        console.log( another.join( " ! " ) );
    }
    return {
        doSomething: doSomething,
        doAnother: doAnother
    };
})();
foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3

 

模块模式另一个简单但强大的变化用法是, 命名将要作为公共 API 返回的对象:

var foo = (function CoolModule(id) {
    function change() {
        // 修改公共 API
        publicAPI.identify = identify2;
    }
    function identify1() {
        console.log( id );
    }
    function identify2() {
        console.log( id.toUpperCase() );
    }
    var publicAPI = {
        change: change,
        identify: identify1
    };
    return publicAPI;
})( "foo module" );
foo.identify(); // foo module
foo.change();
foo.identify(); // FOO MODULE

 

以上是关于作用域闭包《你不知道的JavaScript(上)》的主要内容,如果未能解决你的问题,请参考以下文章

《你不知道的JavaScript》 作用域闭包

《你不知道的JavaScript》整理——作用域提升与闭包

你不知道的JavaScript(作用域和闭包)

JS你不知道的JavaScript 笔记—— 作用域与闭包 - 编译原理 - LHS - RHS - 循环与闭包 - 模块 - 词法作用域 - 动态作用域

你不知道的JavaScript1(作用域与闭包)

你不知道的javascript--上卷--读书笔记2