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

如何理解这句话:以一个例子说明;(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

最新文章

  1. Juniper SSG5 PPTP VPN 619错误解决
  2. CSS 和 JS 动画哪个更快
  3. storm的并发和消息保障性
  4. 4、JavaScript进阶篇①——基础语法
  5. poj2265
  6. [Sparrow OS 设计文档连载(一)] Introduction
  7. 使用sql访问EXECL文件
  8. 数据结构练习 02-线性结构2. Reversing Linked List (25)
  9. iOS UILabel:宽度固定,自动高度显示全部文字
  10. 关于jdbc的一些疑问
  11. 【Bootstrap3.0建站笔记二】button可下拉弹出层
  12. POJ 3237 Tree (树链拆分)
  13. Python函数篇:装饰器
  14. linux安装elk
  15. 学习笔记TF054:TFLearn、Keras
  16. AJAX完整操作
  17. Winform知识汇总之多次绑定DataGridView的DataSource会报错 NullReferenceExcepti
  18. solr 7.7.0配置中文分词器的数据类型
  19. eclipse启动maven项目
  20. 【BZOJ4099】Trapped in the Haybales Gold STL

热门文章

  1. drupal7 判断用户是否具有某个权限
  2. Android Studio 使用Intent实现页面的跳转(带参数)
  3. Pig脚本 .pig
  4. ahjesus wp-autopost破解版,亲测可用
  5. leetCode题解之Reshape the Matrix
  6. 便利的操作plist文件
  7. 用以替换系统NSLog的YouXianMingLog
  8. 适配iOS6与iOS7
  9. IP地址分类/IP地址10开头和172开头和192开头的区别/判断是否同一网段(A、B、C三类地址)【转】
  10. Linux系统更改/关闭防火墙