zoukankan      html  css  js  c++  java
  • JavaScript闭包深入解析

    for (var i=1; i<=5; i++) {
    setTimeout( function timer() {
    console.log( i );
    }, i*1000 );
    }

    ——上面这段代码,如果对JavaScript闭包没有概念的话,将是一头雾水。 by 羊大葱 于2016年10月25日

    几种典型闭包写法

    1、最基础写法

    function foo() {
    var a = 2;
    function bar() {
    console.log( a );
    }
    return bar;
    }
    var baz = foo();
    baz(); // 2 —— 麻麻快看,这就是闭包的效果。

    2、较为变种写法

    function foo() {
    var a = 2;
    function baz() {
    console.log( a ); // 2
    }
    bar( baz );
    }
    function bar(fn) {
    fn(); // 妈妈快看呀,这就是闭包!
    }

     2.1第二种写法简明写法(传递函数间接的传递)

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

     3.直接外面函数引用

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

    将一个内部函数(名为timer)传递给setTimeout(..)。timer 具有涵盖wait(..) 作用域的闭包,因此还保有对变量message 的引用。wait(..) 执行1000 毫秒后,它的内部作用域并不会消失,timer 函数依然保有wait(..)作用域的闭包。

    3.1 直接外面函数引用常见用法

    function setupBot(name, selector) {
    $( selector ).click( function activator() {
    console.log( "Activating: " + name );
    } );
    }
    setupBot( "Closure Bot 1", "#bot_1" );
    setupBot( "Closure Bot 2", "#bot_2" );

    如果你很熟悉jQuery(或者其他能说明这个问题的JavaScript 框架),可以思考3.1的代码。

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

    回到文章一开始的代码

    为什么一直输出的是6呢?

    由于很多开发者对闭包的概念认识得并不是很清楚,因此当循环内部包含函数定义时,代码格式检查器经常发出警告!

    第一、在循环外部函数定义
    function t1(a){console.log(a);}; for(var i=1; i<=5; i++){ setTimeout(t1(i),i*1000); } //----------------------------------------------------------
    第二、直接在循环内部包含函数定义
    for (var i=1; i<=5; i++) {
    setTimeout( function timer() { console.log( i ); }, i*1000 );
    }

      上面两种写法,第一种输出时1、2、3、4、5;第二种写法输入为6,6,6,6,6。

     

    上图是我在两种情况下,当迭代循环到5的时候打出‘d5’,以探究两种情况的执行顺序。很显然,第一种形成闭包情况下,是等迭代全部执行完才开始执行setTimeout();而第二种非闭包情况下是直接每个循环执行的!

  • 相关阅读:
    在独立的文件里定义WPF资源
    Irrlicht 3D Engine 笔记系列 之 教程6- 2D Graphics
    Java实现二叉树的创建、递归/非递归遍历
    NDK在windows下的开发环境搭建及开发过程
    硬件路由转发原理浅析
    ubuntu下vim中内容拷贝到浏览器
    python调用Java代码,完毕JBPM工作流application
    C++组合通信
    linux杂谈(十八):DNSserver的配置(一)
    Codeforces 550D. Regular Bridge 构造
  • 原文地址:https://www.cnblogs.com/lishanyang/p/5997478.html
Copyright © 2011-2022 走看看