zoukankan      html  css  js  c++  java
  • 作用域闭包《你不知道的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
  • 相关阅读:
    【转】 Linux Core Dump 介绍
    【转】 设定linux 系统可用资源
    Python for 循环 失效
    transition 平移属性实现 横向整屏 滚动
    vue 插槽的使用
    vue pc商城仿网易严选商品的分类效果
    干货-vue 中使用 rxjs 进行非父子组件中传值
    vue 2.0 脚手架项目中使用 cross-env 分环境打包
    什么是闭包,有哪些优缺点呢?
    滚动视差
  • 原文地址:https://www.cnblogs.com/linxian95/p/10472960.html
Copyright © 2011-2022 走看看