`
午夜java男
  • 浏览: 8241 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
社区版块
存档分类
最新评论

转一篇关于js闭包的文章

阅读更多

http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html

 

作者: 阮一峰

日期: 2009年8月30日

包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

下面就是我的学习笔记,对于Javascript初学者应该是很有用的。

一、变量的作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

  var n=999;

  function f1(){
    alert(n);
  }

  f1(); // 999

另一方面,在函数外部自然无法读取函数内的局部变量。

  function f1(){
    var n=999;
  }

  alert(n); // error

这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

  function f1(){
    n=999;
  }

  f1();

  alert(n); // 999

二、如何从外部读取局部变量?

出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。

那就是在函数的内部,再定义一个函数。

  function f1(){

    var n=999;

    function f2(){
      alert(n); // 999
    }

  }

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1 就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

  function f1(){

    var n=999;

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999

三、闭包的概念

上一节代码中的f2函数,就是闭包。

各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

四、闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

怎么来理解这句话呢?请看下面的代码。

  function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999

  nAdd();

  result(); // 1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此 nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

五、使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

六、思考题

如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。

代码片段一。

  var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      return function(){
        return this.name;
      };

    }

  };

  alert(object.getNameFunc()());


代码片段二。

  var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };

    }

  };

  alert(object.getNameFunc()());

 

关于最后两段代码,我个人的理解还是有些混乱:

看什么时候整理下

分享到:
评论

相关推荐

    JavaScript知识点总结(十六)之Javascript闭包(Closure)代码详解

    很早就接触过闭包这个概念了,但是一直糊里糊涂的,没有能够弄明白JavaScript的闭包到底是什么,有什么用,今天在网上看到了一篇讲JavaScript闭包的文章(原文链接),讲得非常好,这下算是彻底明白了JavaScript的闭包...

    js闭包引起的事件注册问题介绍

    背景:闲暇时间看了几篇关于js作用域链与闭包的文章,偶然又看到了之前遇到的一个问题,就是在for循环中为dom节点注册事件驱动,具体见下面代码: <!DOCTYPE html> <html> <head> <title>js...

    浅谈JavaScript闭包

    上面那句话听起来可能不是很理解,本人在之前写过一篇Python 闭包小记》的关于 Python 闭包的一些知识的文章,里面写了百度百科对于闭包的理解,虽然由于才疏学浅大部分都是引用的他人的知识架构,但语言这种东西都...

    Javascript的闭包详解

    前言:还是一篇入门文章。Javascript中有几个非常重要的语言特性——对象、原型继承、闭包。其中闭包 对于那些使用传统静态语言C/C++的程序员来说是一个新的语言特性。本文将以例子入手来介绍Javascript闭包的语言...

    顽皮的闭包

    压缩包中的“closure.html”可能是包含了一篇详细讲解闭包的文章或教程,其中可能包括以下知识点: 1. **闭包的基本概念**:解释什么是闭包,它是如何形成的,以及它与作用域的关系。 2. **作用域链**:详细解释...

    JS闭包用法实例分析

    通过对JS闭包用法实例分析这篇文章的标题、描述以及内容部分的阅读,我们可以总结出闭包在JavaScript编程中的运用以及相关知识点。 首先,闭包的定义:在计算机科学中,闭包(Closure)是函数和声明该函数的词法...

    理解javascript函数式编程中的闭包(closure)_.docx

    本篇文章主要探讨JavaScript函数式编程中的一个重要概念——闭包(closure)。闭包是一种特殊的函数,它能记住其定义时的作用域,即使在函数执行完毕后,仍然可以访问到该作用域内的变量。在JavaScript中,每个函数...

    理解Javascript的最好文章

    JavaScript,简称JS,是一种广泛应用于Web开发的轻量级编程语言,它被设计用来操作网页中的HTML、CSS以及用户交互。...对于任何想要深入学习JavaScript的人来说,这都是一篇值得投入时间阅读的文章。

    JavaScript终极指南:一篇掌握所有核心概念技术关键词:JavaScript、回调函数、Promise、async

    内容概要: 这篇文章以幽默诙谐的方式,详细介绍了JavaScript的核心概念和编程技巧...无论你是正在构建一个Web应用,还是准备参加一个编程面试,或者只是对JavaScript感兴趣,这篇文章都能为你提供有价值的信息和指导。

    分析js闭包引起的事件注册问题

    背景:闲暇时间看了几篇关于js作用域链与闭包的文章,偶然又看到了之前遇到的一个问题,就是在for循环中为dom节点注册事件驱动,具体见下面代码: <!DOCTYPE html> <html> <head> <title>...

    js技术文章详细介绍

    本篇文章将深入探讨JavaScript的核心概念和技术,包括但不限于代码实例、原型等关键知识点。 一、JavaScript基础 1. 变量:JavaScript中的变量是动态类型,可以通过var、let或const声明。var适用于全局或函数作用域...

    详解js中let与var声明变量的区别

    JavaScript中的`let`和`var`都是用来声明变量的,但它们之间存在着显著的差异,这些差异主要体现在作用域、变量提升、临时性死区以及重复声明等方面。 1. **块级作用域**: 在ES6之前,JavaScript只有全局作用域和...

    【JavaScript源代码】一篇文章弄懂javascript内存泄漏.docx

    【JavaScript源代码】一篇文章弄懂javascript内存泄漏 在JavaScript中,内存管理对于程序性能至关重要,因为内存泄漏会导致程序效率下降,甚至可能导致应用崩溃。本文旨在深入解析JavaScript中的内存泄漏及其解决...

    js 逆向实战之SM2+SM4

    js 逆向实战之SM2+SM4 是一篇关于 JavaScript 逆向工程实战的文章,主要介绍了 SM2 和 SM4 国产加密算法的实现和应用。下面是相关知识点的总结: 1. JavaScript 逆向工程:文章首先介绍了 JavaScript 逆向工程的...

    JavaScript_Demo,文章《JavaScript笔记》配套代码

    这篇文章《JavaScript笔记》的配套代码提供了丰富的实例,旨在帮助读者深入理解和掌握JavaScript的基本概念、语法以及应用技巧。 首先,我们来看看“JS笔记”部分。在学习JavaScript时,理解变量的声明、数据类型...

    Javascript学习笔记之 函数篇(三) : 闭包和引用

    闭包和引用是JavaScript中的核心概念之一。闭包允许一个函数访问并操作函数外部的变量,这种特性极大地增强了JavaScript语言的表达能力。通过使用闭包,开发者可以创建出模拟私有变量的效果,实现数据封装和模块化...

    JavaScript学习笔记之总结与回顾(学习JavaScript基础知识看这一篇就够了,文章总字数2.8万)源码

    这篇“JavaScript学习笔记之总结与回顾”涵盖了从基础到进阶的广泛内容,总计2.8万字,旨在为学习者提供一个全面的理解JavaScript的平台。 在学习JavaScript时,首先会接触的是基本的语法结构,包括常量、变量和...

    javascript中巧用“闭包”实现程序的暂停执行功能

    在这篇文章中,我们将通过三个示例来展示如何使用闭包实现程序的暂停执行功能。 什么是闭包? 在了解闭包之前,我们需要先了解javascript 中的函数。javascript 中的函数是一个特殊的对象,它可以被作为另一个函数...

Global site tag (gtag.js) - Google Analytics