javascript---我对闭包的理解

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

       如何理解这句话:以一个例子说明;(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
在程序媛的路上,越走越用劲儿:)
原文地址:https://www.cnblogs.com/AliceX-J/p/5226297.html