JavaScript--我所理解的闭包

关于闭包大家肯定不陌生, 刚知道闭包这个特性那会真的被折磨, 现在找个时间把这些都记下来, 希望能帮新人理解和记忆.

-------------------------------------------------------------------------------------------

闭包的格式有很多种, 但基本都是将一个嵌套函数中的内层函数返回到外层函数外面, 使外层函数体外也能访问和操作外层函数中"封住"的局部变量, 与此同时, 外层函数中的变量不会被销毁, 会"长久记忆".

最常见的闭包:

function outer(){
    var i = 100;              //保存于外层函数体内的局部变量
    return function(){     //用于返回内部函数
          console.log(i);   //内部函数体中对 "它" 自己的上下文中的变量进行了操作
    }
}
    var inner = outer();
    inner();    

闭包的形式知道了, 重点是怎么调用, 关于调用的方式有很多:

第一种:

function outer(){
    var i = 100;
    return function(){
          i++;         
          console.log(i);  
    }
}
    var inner1 = outer();
    var inner2 = outer();
    inner1();  //输出结果为 101;
    inner2();  //输出结果还是 101;

这是为何呢? 原因是  当 外层函数每执行一次, 就会创建新的闭包, 即每次外层函数的执行都开辟新的内存空间, 虽然 inner1 和 inner2 都是函数的引用, 但每次返回的函数都是"新的", 所以 inner1 是 inner1, inner2 是 inner2.

第二种

function outer(){
    var i = 100;
    return function(){
          i++;         
          console.log(i);  
    }
}
    var inner1 = outer();
    var inner2 = inner1;
    inner1(); //输出 101
    inner2(); //输出 102

这种调用方式和第一种相比就很好理解了, 因为 inner1 和 inner2 都是"同一个函数"的引用, 所以出现 101 和 102 也就通了.

第三种

function fo(){
    var i = 0;
    return function(n){
    return n + i++;
    }
}

var f = fo();      //现在变量f是一个函数的引用
var a = f(15);     //输出 15, i此时的值是0, 不是undefind, 闭包能够记住自己认识变量i
var b = fo()(15);  //输出 15, fo()会返回新的内层函数, 也就是说产生了新的闭包(对比第一种理解), i已经被清零
var c = fo()(20);  //输出 20, 同理
var d = f(20);    //输出 21

第三种函数做了稍稍改变, 内层函数中要传入形式参数, 其实道理是一样的.

第四种

function fo(m){
    return function(n){
    return m + n;
    }
}

var f = fo(1);      //变量 f 是一个内层函数的引用, 此时 f 已"记住" f 自己中要调用的 m 的值为 1
var a = f(2);       //输出 3, 因为闭包的存在, 所以在 f(2) 执行时, f 内部的 m 是 1
var b = fo(10)(1);  //输出 11, 每当外层函数 fo 执行一次, 都会产生新的闭包并返回一个函数
var c = fo(10)(2);  //输出 12。同理。
var d = f(3);       // 和 f(2) 同理.

第五种

其实第五种来说, 不单单是闭包的影响, 还有就是关于"异步"的一些概念, 就是浏览器给元素添加监听是要消耗时间的, 所以在给一个类数组中的元素通过循环添加监听是不能直接添加的.下面是 html 结构.

    <ul>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>

下面是对应的 JS 代码:


var lis = document.getElementsByTagName("li");
for(var i = 0, length = lis.length; i < length; i++){
  lis[i].onclick = function (){
    console.log("我被点击了, 我是第" + i);
  };
}

初学者可以试试, 会发现每个 li 触发点击后再控制台输出的都是 "我被点击了, 我是第 5", 原因是 当 浏览器给 元素添加监听时, 不会阻塞程序的执行, 就是说在给 lis[0] 添加事件监听时, for 循环还在走, i 还在 ++.

解决方法最好用的就是 IIFE(即立即执行函数):

var lis = document.getElementsByTagName("li");
for(var i = 0, length = lis.length; i < length; i++){
    lis[i].onclick = (function(i){
                return function (){
                    console.log("我被点击了, 我是第" + i);
                                };
            })(i);
}        

外层函数是立即执行的, 并且把 i 当做参数传入函数体, 因此返回的内层函数就会拿到"合适的" i 值.

以上是我对闭包的一些理解, 在此抛砖引玉, 有误导之处还请不吝指点 ^^.

时间: 2024-10-23 08:35:58

JavaScript--我所理解的闭包的相关文章

javascript深入理解js闭包(看了挺多的,感觉这篇比较透彻)

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function

JavaScript函数,作用域以及闭包

JavaScript函数,作用域以及闭包 1. 函数 (1). 函数定义:函数使用function关键字定义,它可以用在函数定义表达式或者函数声明定义. a. 函数的两种定义方式: * function functionName() {} * var functionName = function(){} b. 两种函数定义不同之处 1). 声明提前问题 函数声明语句   :声明与函数体一起提前 函数定义表达式 :声明提前,但是函数体不会提前 请看下面图示:绿色线上面实在js初始加载的时候,查看

JavaScript大杂烩6 - 理解JavaScript中的this

在JavaScript开发中,this是很常用的一个关键字,但同时也是一个很容易引入bug的一个关键字,在这里我们就专门总结一下页面中可能出现的this关键字(包括几种在其他页面文件中出现的this). JavaScript中的this关键字通常只使用在函数中,它指向当前函数的调用者,这是this关键字的本质,所有的使用方式都是围绕这个展开的,让我们来看一下在各种性质的函数中this的用法.1. 在对象的函数中使用this var person = { name: 'Frank', say: f

【javascript基础】8、闭包

原文:[javascript基础]8.闭包 前言 函数和作用域啥的我们前面已经了解了,现在就要学习闭包了,这是一个挺晦涩的知识点,初学者可能会感觉不好理解,但是高手都不不以为然了,高手就给我提点意见吧,我和新手一起来学习什么是闭包. 例子 先不说定义,先看一个题,看看大家能得出正确的结果不, function test(){ var arr = []; for(var i = 0;i<10;i++){ arr[i] = function(){ return i; } } return arr;

理解js闭包原理

各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂.我的理解是,闭包就是能够读取其他函数内部变量的函数. 由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数". 所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁. 闭包可以用在许多地方.它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中. 怎么来理解这句话呢?请看下面的

JavaScript大杂烩9 - 理解BOM

毫无疑问,我们学习JavaScript是为了完成特定的功能.在最初的JavaScript类型系统中,我们已经分析过JavaScript在页面开发中充当着添加逻辑的角色,而且我们知道JavaScript不仅仅包含基本的语法规范.下面我们就重点看一下JavaScript在页面中干的那些事.总的来说,JavaScript在页面端就干两件事:操作DOM与操作BOM (当然了向Server获取数据也是它的工作,不过获取到数据后还是回来干这两件事,大家对JavaScript最直接的印象应该就是各种光怪陆离的

JavaScript中的函数与闭包

转自javascript深入理解js闭包_javascript技巧_脚本之家 http://www.jb51.net/article/24101.htm 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; fu

JS javascript面向对象的理解及简单的示例

javascript面向对象的理解及简单的示例 一. javascript面向对象概念: 为了说明 JavaScript 是一门彻底的面向对象的语言,首先有必要从面向对象的概念着手 , 探讨一下面向对象中的几个概念: 1.一切事物皆对象 2.对象具有封装和继承特性 3.对象与对象之间使用消息通信,各自存在信息隐藏 以这三点做为依据,C++ 是半面向对象半面向过程语言,因为,虽然他实现了类的封装.继承和多态,但存在非对象性质的全局函数和变量.Java.C# 是完全的面向对象语言,它们通过类的形式组

我所理解的‘闭包’

一.什么是闭包? 我相信有很多小伙伴和我一起,找了很多‘闭包’的字面解释,当时看了之后,感觉记住了.但是过段时间又忘了‘闭包’是什么了?所以现在你就只用记住一句话:“闭包允许函数访问局部作用域之外的数据”. 现在我们来看一段闭包的代码: function makeName (){ let name = 'zhangsan'; function displayName(){ alert(name); } return displayName; } var fun = makeName(); fun

前端学习 第六弹: javascript中的函数与闭包

前端学习 第六弹:  javascript中的函数与闭包 当function里嵌套function时,内部的function可以访问外部function里的变量 function foo(x) {    var tmp = 3;    function bar(y) {        alert(x + y + (++tmp));    }    bar(10);}foo(2) 这时无论怎么运行输出的都是16,但这不是闭包 如果我们返回内部函数,内部function会close-over外部fu