一、闭包
       闭包是一种特殊的对象。它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成

如何理解这句话:以一个例子说明;(from MDN)

function makeFunc() {

var name = "Mozilla";

function displayName() {
alert(name);
}
return displayName;
}

var myFunc = makeFunc();

myFunc();

在这个函数中 myFunc就是闭包,因为:1.它是一个函数,2,它的环境是被创建闭时在作用域中的任何局部变量组成(makeFunc函数的局部环境+全局环境+displayName自己的环境)。

作用域补充

http://www.jb51.net/article/30706.htm.
我的总结为:普通函数的作用域包括全局对象,和自己的活动对象(自己的局部都对象)。当函数销毁后,作用域也被销毁。
闭包:将创建它的函数(外部函数)的活动对象添加到自己的作用域链中,更重要的是,此种情况下外部函数执行完毕后,其活动对象不会被摧毁,
因为匿名函数的作用域链仍然在引用这个活动对象(活动对象就会留在内存中)直到该闭包对象被销毁。

 

二、闭包的应用

摘自MDN (已经验证,一定要敲一遍)我摘写我学到的部分,该文章中的实用的闭包的例子我觉得不适用,没得必要这么用,而且内存一直被占着。虽然占的内存很小。所以闭包还是要尽量不用。

https://developer.mozilla.org/cn/docs/Web/JavaScript/Closures

1.用闭包模拟私有方法

var Counter = (function()

{ var privateCounter = 0;

function changeBy(val) { privateCounter += val; }

return {

increment: function() { changeBy(1); },

decrement: function() { changeBy(-1); },

value: function() { return privateCounter; } } })();

console.log(Counter.value()); /* logs 0 */

Counter.increment();

Counter.increment();

console.log(Counter.value()); /* logs 2 */

Counter.decrement();

console.log(Counter.value()); /* logs 1 */


这个地方有个重点是,因为函数自执行了,只有一个执行环境,所以内部的匿名函数共享这个环境。
这样外部无法访问变量privateCounter,和changeBy方法,只能通过返回的对象里的方法来访问,和操作私有变量和私有方法。模拟私有方法。

2.在循环中创建闭包

直接例子说话:

function createFun(){

var result = new Array();

for (var i =0;i<10;i++){

result[i]=function(){

return i;

};

}

return result;

}

该函数返回的是一个函数数组,每个函数都会返回10,因为每个函数的作用域链中都保存着createFun的活动对象,所以它们引用的都是同一个变量i。此时每个函数都引用着保存变量i的同一个变量,createFun执行后,i=10;

解决方法

创建一个匿名函数

function createFun(){

var result = new Array();

for (var i =0;i<10;i++){

result[i]=function(num){

return function(){

return num;

}

}(i);

}

return result;

}

能行的原因:1.在createFun中立即执行该匿名函数的结果赋给数组,这里的匿名函数有个参数,参数按值传递。所以就将变量i的当前值复制给num,在匿名函数的内部,又创建并返回了一个访问num的闭包。所以result数组中的每个函数都有自己num变量的一个副本,因此就可以返回各自不同的数值。

3.模拟bind,函数柯里化

ECMAScript5中为函数定义了一个原生的bind方法,由于只支持IE9+、Firefox4+、Chrome所以可以自己利用闭包写一个原生的。

if(!Function.prototype.bind){

  //context是函数被绑定的环境
  Function.prototype.bind = function(context){
    var that = this;
    //返回一个闭包,由于闭包能保留外部作用域的引用,在这个例子中就是保留了that
    return function (){
      return that.apply(context,arguments);
    }
  }
}

函数柯里化,用于串讲已经设置好了一个或多个参数的函数。

function curry(fn){

  //args保留设置好的的参数

  var args = Array.prototype.slice.call(arguments,1);

  return function (){

    var innerArgs = Array.prototype.slice.call(arguments);

    var finalArgs = args.concat(innerArgs);
    return fn.apply(null,finalArgs);
  }
}
function add(num1,num2){
  return num1+num2;
}
var curriedAdd = curry(add,5);
alert(curriedAdd(4)); // 9

javascript---我对闭包的理解的更多相关文章

  1. 讲解JavaScript中对闭包的理解

    1.JS中变量的作用域 在理解闭包之前,我们得弄清楚JS中变量的作用域原理,它分为全局作用域和局部作用域,它有一个特点就是局部可以获取全局的声明变量,而全局却不能得到局部声明的变量,我们先来看一个小例 ...

  2. JavaScript中对于闭包的理解

    1.什么是闭包? 闭包,官方对闭包的解释是:一个拥有很多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 闭包的特点: (1).作为一个函数变量的一个引用,当函 ...

  3. JavaScript面向对象之闭包的理解

    首先了解一下什么是闭包,闭包是一个函数,通常被称为闭包函数或者绑定函数,该函数运行在一个特殊的环境里,该环境定义了一些本地变量,当该函数被调用时,仍可以使用这些本地变量. 当一个函数在不位于它所处的环 ...

  4. [Python]闭包的理解和使用

    闭包广泛使用在函数式编程语言中,虽然不是很容易理解,但是又不得不理解. 闭包是什么? 在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包.闭包可以 ...

  5. JavaScript学习总结——我所理解的JavaScript闭包

    一.闭包(Closure) 1.1.什么是闭包? 理解闭包概念: a.闭包是指有权限访问另一个函数作用域的变量的函数,创建闭包的常见方式就是在一个函数内部创建另一个函数,也就是创建一个内部函数,创建一 ...

  6. 深入理解javascript原型和闭包 (转)

    该教程绕开了javascript的一些基本的语法知识,直接讲解javascript中最难理解的两个部分,也是和其他主流面向对象语言区别最大的两个部分--原型和闭包,当然,肯定少不了原型链和作用域链.帮 ...

  7. 深入理解javascript原型和闭包系列

    从下面目录中可以看到,本系列有16篇文章,外加两篇后补的,一共18篇文章.写了半个月,从9月17号开始写的.每篇文章更新时,读者的反馈还是可以的,虽然不至于上头条,但是也算是中规中矩,有看的人,也有评 ...

  8. 深入理解javascript原型和闭包(1)——一切都是对象

    “一切都是对象”这句话的重点在于如何去理解“对象”这个概念. ——当然,也不是所有的都是对象,值类型就不是对象. 首先咱们还是先看看javascript中一个常用的函数——typeof().typeo ...

  9. 深入理解javascript原型和闭包(2)——函数和对象的关系

    上文(理解javascript原型和作用域系列(1)——一切都是对象)已经提到,函数就是对象的一种,因为通过instanceof函数可以判断. var fn = function () { }; co ...

  10. 深入理解javascript原型和闭包(3)——prototype原型

    既typeof之后的另一位老朋友! prototype也是我们的老朋友,即使不了解的人,也应该都听过它的大名.如果它还是您的新朋友,我估计您也是javascript的新朋友. 在咱们的第一节(深入理解 ...

随机推荐

  1. Math.random理解练习

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  2. keras Lambda 层

    Lambda层 keras.layers.core.Lambda(function, output_shape=None, mask=None, arguments=None) 本函数用以对上一层的输 ...

  3. 网络基础 Windows telnet使用简介及相关问题解决方案

    Windows telnet使用简介及相关问题解决方案 by:授客 QQ:1033553122 更改telnet的默认端口(23)(仅适用XP) 步骤: 进入cmd控制窗口 tlntadmn conf ...

  4. maven 生命周期、生命周期阶段、插件、目标

    生命周期maven的生命周期是抽象的,它本身不做任何实际的工作.实际的工作都由插件来完成.生命周期好比接口,插件好比实现类.maven 有三个独立的生命周期,clean.default.site. 生 ...

  5. 【日常记录】【unity3d】 OnTriggerEnter 和 OnCollisionEnter (2D) 的区别

    问题:两个物体A,B 两者都有碰撞体 collider(Box Collider,Sphere Collider,Capsule Collider等)当两物体相撞时,会进入 OnTriggerEnte ...

  6. Python DDT(data driven tests)模块心得

    关于ddt模块的一些心得,主要是看官网的例子,加上一点自己的理解,官网地址:http://ddt.readthedocs.io/en/latest/example.html ddt(data driv ...

  7. C#下使用XmlDocument详解

    XML在开发中作为文件存储格式.数据交换的协议用的非常普遍,各个编程语言有都支持.W3C也制定了XML DOM的标准.在这里主要介绍下.Net中的XmlDocument,包括xml读取和写入等功能.一 ...

  8. [转] iOS文字排版(CoreText)那些事儿

    文章转载自 http://www.cocoachina.com/applenews/devnews/2014/0521/8504.html iOS文字排版(CoreText)那些事儿 转自阿毛的蛋疼地 ...

  9. UITabBar设置详解

    UITabBar设置详解 效果图 说明 1. 设置tabBarItem中的图片以及标题 2. 设置标题文本样式 3. 修改tabBar背景色 源码 https://github.com/YouXian ...

  10. Hyper-v 中 CentOS 连接外网之有线网卡

    一.打开虚拟机交换管理器,查看默认的虚拟交换机 如果不是内部网络,则需要新建一个虚拟交换机,新的交换机应该使用内部网络: 二.配置虚拟机使用的交换机.如果 “默认开关” 不是内部网络,需要使用自己新创 ...