YvetteLau/Step-By-Step

什么是闭包?闭包的作用是什么?

Opened this issue · 39 comments

什么是闭包?闭包的作用是什么?

first, 沙发沙发

切入正题,闭包,可以理解为作用域链的延伸;

通过自执行函数将函数作用域变量通过api的方式暴露出来,这种方式并不会创建全局变量,这种操作既可以访问局部变量,同时还限制了变量的复写,大部分模块都是基于此实现,由局部变量与外部获取共同构成了闭包。理解浅显,还请大佬指正.

闭包:
a:通过作用域链
b:垃圾回收机制
这两者相结合而产生了闭包这个概念,函数内部的变量能够让函数外部访问到

闭包是什么?

闭包有三步: 第一,外层函数嵌套内层函数; 第二, 内层函数使用外层函数的局部变量; 第三,把内层函数作为外层函数的返回值! 经过这样的三步就可以形成一个闭包! 闭包就可以在全局函数里面操作另一个作用域的局部变量!

闭包的作用?

闭包既能重复使用局部变量,又不污染全局!

闭包是有权访问另一个函数作用域中的变量的函数:当函数1向外暴露了可以改变内部局部变量的方法(内部匿名函数,外部函数2接受匿名函数,匿名函数作用域链在初始化时包含了函数1的变量对象,可以调用函数1所有的内部变量。一般函数执行完局部活动对象就会进行销毁,内存仅仅只会保存全局作用域,但函数1在执行完毕其活动对象也不会进行销毁,因为匿名函数的作用域链仍然在对其进行调用。(参考高程
作用:可以读取函数内部的变量,让变量的值始终保持在内存中。栗子:实现函数curry化。
注意:内存泄露。

js采用的是词法作用域,也就是函数可以访问的变量在函数定义时写在哪里就确定了和函数被调用的位置无关。闭包就是函数不在定义的词法作用域内被调用,但是仍然可以访问词法作用域中定义的变量

闭包可以被用在三个地方:

  • 封装私有变量
// name 只能通过getName接口来访问
function Person(name) {
    this.getName = function() {
        return name;
    }
}
  • 模拟模块
function module() {
    let inner = 1;
    let increaseInner = function() {
        inner++;
    }
    let decreaseInner = function() {
        inner--;
    }
    let getInner = function() {
        return inner;
    }
    return {
        increaseInner,
        decreaseInner,
        getInner
    }
}
let api = module();
console.log(api.getInner());
api.increaseInner();
console.log(api.getInner());
api.decreaseInner();
console.log(api.getInner());
  • 用在块作用域上
for (var i = 0; i < 5; i++) {
    (function(i) {
        setTimeout(function() {
            console.log(i)
        }, 1000);
    })(i);
}

当内部函数被保存到外部时,就会形成闭包;
闭包会导致原有作用域链不释放,造成内存泄露;
闭包作用:

  • 实现公有变量,比如说函数累加器
  • 做缓存
  • 实现属性的私有化

从定义上讲 : 闭包其实是一个绑定了执行环境的函数,所以广义的闭包其实就对应了JS中的函数。

它的执行环境是函数词法环境,由环境记录器和作用域链组成。

而通常我们所讲的闭包是在一个函数 A 内部有一个函数 B,通过函数 B 记录访问函数 A 内的变量。

因为作用域的关系,函数A外部无法直接访问内部数据,而通过闭包这种方法可以让我们可以间接访问

函数内部的私有变量,利用这一特性我们可以用来封装私有变量,实现数据寄存等

闭包就是有权在一个函数去访问另一个函数的变量。通常是在一个函数内部创建一个函数。
作用:
封装私有变量。
实现JS的代码块。

我理解的闭包是:一个函数在另外一个函数中,这个内部函数使用外部函数的局部变量,并且内部函数被所在函数以外的地方调用。这个内部函数就被称为闭包。
利用闭包我们可以把局部变量和外部连接起来。让外部得以访问;同时这个局部变量会一直保存在内存当中,不会随着外部函数的调用完成而销毁。
哪里理解有误,有劳大佬们指出!

红宝书里面说:“闭包就是指有权访问另一个函数作用域中的变量的函数“。
圣经宝典里面说:”从技术的角度来讲,所有的JavaScript函数都是闭包;它们都是对象,它们都关联到作用域链“。
You dont't know JS say:"当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是当前词法作用域之外执行".

只要存在调用内部函数的可能,js就需要保存被引用的函数。js运行时需要跟踪引用到的这个内部函数的所有变量,一直到最后一个变量废除,js的GC才能回收这些变量的内存空间。

作用:

  1. 读取函数内部的变量
  2. 让这些变量值始终保存在内存中

要理解闭包,必须了解JS特殊的变量作用域。
变量的作用域:全局变量和局部变量
在函数内部可以直接读取全局变量

var n=999
function f1(){
alert(n)
}
f1();//999

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

 function f1(){
    var n=999;
  }

  alert(n); // error

我们有时候需要得到函数内的局部变量,那要怎么办呢?
那就是在函数的内部再定义一个函数

 function f1(){

    var n=999;

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

  }

上面的函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来不行,f2内部的局部变量,对f1是不可见的。这就是JS语言特有的链式作用域结构,子对象会一级一级地向上寻找所有父对象的变量。

既然f2可以读取f1中的局部变量,只要把f2作为返回值返回,在f1内部就可以读取它的内部变量了。

function f1(){

    var n=999;

    function f2(){
      alert(n); 
    }

    return f2;

  }

  var result=f1();

  result(); // 999

闭包的概念
闭包就是定义在一个函数内部的函数,就是将函数内部和函数外部连接起来的桥梁。
闭包的用处
1.读取函数内部变量
2.让这些变量的值始终保持在内存中

function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999

  nAdd();

  result(); // 1000



参考连接:
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html

什么是闭包?

因为js作用域的问题,函数内部可以访问函数外部的变量,而函数外部不能访问函数内部的变量,有时我们需要访问函数内部的变量,这就需要在函数内部返回一个函数,返回需要访问的变量。这就是闭包。
即闭包就是有权访问一个函数的内部变量,通常是在函数内部返回一个函数。

闭包的作用

1、属性私有化
2、实现模块化
3、块级作用域

什么是闭包?
闭包就是能够读取其他函数内部变量的函数.在本质上,闭包是将函数内部和函数外部连接起来的桥梁.
闭包的作用?
1.读取函数内部变量
2.让这些变量的值始终保持在内存中
3.实现块级作用域

闭包定义:

当函数可以记住并访问所在的词法作用域,就产生了闭包。即使函数是在当前词法作用域之外执行。
闭包使得函数在外部调用时,可以继续访问定义时的词法作用域。
只要使用了回调函数,实际上就是在使用闭包!
—— 摘自《你所不知道的js》

简单来说就是:

  • 父函数的返回值是一个子函数
  • 子函数可以访问父函数中的作用域

缺陷:

  • 闭包引用了祖先函数的作用域,所以滥用闭包会有内存问题
  • 让函数的变量都保存在内存中,内存消耗变大。使用不当会造成内存泄漏

作用

  • 封装块级作用域
// IIFE的目的是为了隔离作用域,防止污染全局命名空间。
(function() {
    //这里是块级作用域
})();
  • 封装私有变量

闭包问题

定义

你不知道的js 书是这样定义的:当函数可以记住并访问所在的词法作用域时就产生的了闭包,即使函数是在当前词法作用域之外执行。

function foo() {
    var a = 2
    function bar() {
        console.log(a)
    }
    return bar
}
var baz = foo()

bar 能使foo的内部作用域不会在foo()执行后立即被销毁,会一直存活,以便bar() 后续进行使用。

讲个故事:一对情侣去酒店开房!到了晚上要做就要做该做的事情,嘿嘿嘿的那种。门房禁闭。窗户窗帘拉上,从外面绝对看不到房间内状况。但是万恶的酒店老板是在房间内装了隐形摄像头(闭包)...老板通过摄像头能清楚的看到大战状况...

JavaScript采用词法作用域,即函数能访问的作用域是定义它的时候就决定了.
定义
闭包就是在函数内部在定义一个函数,因为是词法作用域,所以闭包函数可以访问定义时的函数内部的变量.当闭包函数在任意位置执行时都可以访问外层函数内部的变量.使变量可以常驻内存.\

作用:

  • 封装私有变量
  • 实现模块化
  • 块级作用域

1. 闭包的定义

外层函数嵌套内层函数, 内层函数使用外层函数的局部变量,把内层函数作为外层函数的返回值。

function A() {
   let a = 1
   function B() {
      console.log(a)
  }
  return B
 }

2.闭包的应用

用闭包解决递归问题

 function  factorial(num) {
    if(num<= 1) {
        return 1;
    } else {
       return num * factorial(num-1)
    }
 }
 var anotherFactorial = factorial
 factorial = null
 anotherFactorial(4)   // 报错 。
 //最好是return num* arguments.callee(num-1),arguments.callee指向当前执行函数,但是在严格模式下不能使用该属性也会报错,所以借助闭包来实现

 // 使用闭包实现递归
 function newFactorial = (function f(num){
     if(num<1) {return 1}
     else {
        return num* f(num-1)
     }
 }) 
 //这样就没有问题了,实际上起作用的是闭包函数f,而不是外面的函数newFactorial

用闭包模仿块级作用域

  • 例1:

    for(var i=0; i<10; i++){
         console.log(i)
    }
    alert(i)  // 变量提升,弹出10
    
    //为了避免i的提升可以这样做
    (function () {
        for(var i=0; i<10; i++){
             console.log(i)
        }
    )()
    alert(i)   // undefined   因为i随着闭包函数的退出,执行环境销毁,变量回收
    
  • 例2:

    for (var i = 0; i < 5; i++) {
        (function(i) {
            setTimeout(function() {
                console.log(i)
            }, 1000);
        })(i);
    }
    

封装私有变量

   function create_counter(initial) {
        var x = initial || 0;
        return {
            inc: function () {
                x += 1;
                return x;
            }
        }
   }
   var c1 = create_counter();
   c1.inc(); // 1
   c1.inc(); // 2
   c1.inc(); // 3

   var c2 = create_counter(10);
   c2.inc(); // 11
   c2.inc(); // 12
   c2.inc(); // 13

在返回的对象中,实现了一个闭包,该闭包携带了局部变量x,并且,从外部代码根本无法访问到变量x。换句话说,闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来。

3.闭包的作用

  • 读取函数内部变量

  • 让变量的值始终保持在内存中

4.闭包的注意事项

通常,函数的作用域及其所有变量都会在函数执行结束后被销毁,被垃圾回收机制回收。但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止。

  function makeAdd(x) {
    return function(y) {
      return x + y;
    };
  }

  var add1 = makeAdder(5);
  var add2 = makeAdder(10);

  console.log(add1(4));  // 9
  console.log(add2(3)); // 13

  // 释放对闭包的引用
  add5 = null;
  add10 = null;

闭包只能取得包含函数中任何变量的最后一个值,这是因为闭包所保存的是整个变量对象,而不是某个特殊的变量。

  function test(){
    var arr = [];
    for(var i = 0;i < 10;i++){
      arr[i] = function(){
        return i;
       };
    }
    for(var a = 0;a < 10;a++){
       console.log(arr[a]());
    }
  }
  test(); // 连续打印 10 个 10

闭包中的this

 var name = "The Window";
 var obj = {
     name: "My Object",
     getName: function(){
         return function(){
             return this.name;
      };
     }
   };
   console.log(obj.getName()());  // The Window
   //将这一部分解:console.log( function(){return this.name;};() ); 

改变作用域

 var name = "The Window";
 var obj = {
   name: "My Object",
   getName: function(){
       var that = this;
       return function(){
          return that.name;
      };
    }
 };
 console.log(obj.getName()());  // The Window
 //将这一部分解:console.log( function(){return this.name;};() ); 

5.闭包的缺点

  • 闭包的缺点就是常驻内存会增大内存使用量,并且使用不当很容易造成内存泄露。

  • 如果不是因为某些特殊任务而需要闭包,在没有必要的情况下,在其它函数中创建函数是不明智的,因为闭包对脚本性能具有负面影响,包括处理速度和内存消耗。

6.关于闭包的面试题

第一个JS闭包问题

function fun(n,o) {
  console.log(o)
  return {
    fun:function(m){
      return fun(m,n);
    }
  };
}
var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);//undefined,?,?,?
var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,?
var c = fun(0).fun(1);  c.fun(2);  c.fun(3);//undefined,?,?,?
//问:三行a,b,c的输出分别是什么?

//答案:
//a: undefined,0,0,0
//b: undefined,0,1,2
//c: undefined,0,1,1

(1)先确定这三个函数的关系

这段代码中出现了三个fun函数,所以第一步先搞清楚,这三个fun函数的关系,哪个函数与哪个函数是相同的。

function fun(n,o) {
  console.log(o)
  return {
    fun:function(m){
      //...
    }
  };
}

先看第一个fun函数,属于标准具名函数声明,是新创建的函数,他的返回值是一个对象字面量表达式,属于一个新的object。这个新的对象内部包含一个也叫fun的属性,通过上述介绍可得知,属于匿名函数表达式,即fun这个属性中存放的是一个新创建匿名函数表达式。

注意:所有声明的匿名函数都是一个新函数。

所以第一个fun函数与第二个fun函数不相同,均为新创建的函数。最内层的return出去的fun函数不是第二层fun函数,是最外层的fun函数。所以,三个fun函数的关系也理清楚了,第一个等于第三个,他们都不等于第二个。

(2)函数是怎样调用的

为了方便看把代码重新写一下

function fun(n,o) {
  console.log(o)
  return {
    fun:function(m){
      return fun(m,n);
    }
  };
}
var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);//undefined,?,?,?
var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,?
var c = fun(0).fun(1);  c.fun(2);  c.fun(3);//undefined,?,?,?
//问:三行a,b,c的输出分别是什么?

第一行 a

var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);

第一个fun(0)是在调用第一层fun函数。第二个fun(1)是在调用前一个fun的返回值的fun函数,所以:第后面几个fun(1),fun(2),fun(3),函数都是在调用第二层fun函数。

遂:

  • 在第一次调用fun(0)时,o为undefined;

  • 第二次调用fun(1)时m为1,此时fun闭包了外层函数的n,也就是第一次调用的n=0,即m=1,n=0,并在内部调用第一层fun函数fun(1,0);所以o为0;

  • 第三次调用fun(2)时m为2,但依然是调用a.fun,所以还是闭包了第一次调用时的n,所以内部调用第一层的fun(2,0);所以o为0。

  • 第四次同理;

即:最终答案为 undefined,0,0,0

第二行 b

var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,?

先从fun(0)开始看,肯定是调用的第一层fun函数;而他的返回值是一个对象,所以第二个fun(1)调用的是第二层fun函数,后面几个也是调用的第二层fun函数。

遂:

  • 在第一次调用第一层fun(0)时,o为undefined;

  • 第二次调用 .fun(1)时m为1,此时fun闭包了外层函数的n,也就是第一次调用的n=0,即m=1,n=0,并在内部调用第一层fun函数fun(1,0);所以o为0;

  • 第三次调用 .fun(2)时m为2,此时当前的fun函数不是第一次执行的返回对象,而是第二次执行的返回对象。而在第二次执行第一层fun函数时时(1,0)所以n=1,o=0,返回时闭包了第二次的n,遂在第三次调用第三层fun函数时m=2,n=1,即调用第一层fun函数fun(2,1),所以o为1;

  • 第四次调用 .fun(3)时m为3,闭包了第三次调用的n,同理,最终调用第一层fun函数为fun(3,2);所以o为2;

即最终答案:undefined,0,1,2

第三行 c

var c = fun(0).fun(1);  c.fun(2);  c.fun(3);//undefined,?,?,?

根据前面两个例子,可以得知:

fun(0)为执行第一层fun函数,.fun(1)执行的是fun(0)返回的第二层fun函数,这里语句结束,遂c存放的是fun(1)的返回值,而不是fun(0)的返回值,所以c中闭包的也是fun(1)第二次执行的n的值。c.fun(2)执行的是fun(1)返回的第二层fun函数,c.fun(3)执行的也是fun(1)返回的第二层fun函数。

遂:

  • 在第一次调用第一层fun(0)时,o为undefined;

  • 第二次调用 .fun(1)时m为1,此时fun闭包了外层函数的n,也就是第一次调用的n=0,即m=1,n=0,并在内部调用第一层fun函数fun(1,0);所以o为0;

  • 第三次调用 .fun(2)时m为2,此时fun闭包的是第二次调用的n=1,即m=2,n=1,并在内部调用第一层fun函数fun(2,1);所以o为1;

  • 第四次.fun(3)时同理,但依然是调用的第二次的返回值,遂最终调用第一层fun函数fun(3,1),所以o还为1

即最终答案:undefined,0,1,1

第二个JS闭包问题

循环中使用闭包解决 var 定义函数的问题

for ( var i=1; i<=5; i++) {
	setTimeout( function timer() {
		console.log( i );
	}, i*1000 );
}

首先因为 setTimeout 是个异步函数,所有会先把循环全部执行完毕,这时候 i就是 6 了,所以会输出一堆 6。

解决办法两种,第一种使用闭包

for (var i = 1; i <= 5; i++) {
  (function(j) {
    setTimeout(function timer() {
      console.log(j);
    }, j * 1000);
  })(i);
}

第二种就是使用 setTimeout 的第三个参数

for ( var i=1; i<=5; i++) {
	setTimeout( function timer(j) {
		console.log( j );
	}, i*1000, i);
}

第三种就是使用 let 定义 i 了

for ( let i=1; i<=5; i++) {
	setTimeout( function timer() {
		console.log( i );
	}, i*1000 );
}

因为对于 let 来说,他会创建一个块级作用域,相当于

{ // 形成块级作用域
  let i = 0
  {
    let ii = i
    setTimeout( function timer() {
        console.log( ii );
    }, i*1000 );
  }
  i++
  {
    let ii = i
  }
  i++
  {
    let ii = i
  }
  ...
}

借用《你不知道的javascript》上的一句话:当函数可以记住并访问其所在的词法作用域,即使该函数在其词法作用域之外执行,这时就产生了闭包。

闭包是什么?

闭包就是有权访问另一个函数作用域中的变量的函数。

闭包的作用?

  • 变量私有化
  • 模块封装
lqzo commented

什么是闭包?

闭包是函数和声明该函数的词法环境的组合。

闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。

函数工厂
这是MDN上的一个示例。

闭包的作用是什么?

模拟私有方法,定义公共函数(模块模式),以及上例中的函数工厂。使用闭包可以实现这些功能,这样回答闭包的作用不知道是否恰当。楼上同学对于作用的回答可能更合适一些。

性能考量

如果不是某些特定任务需要使用闭包,在其它函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响。
例如,在创建新的对象或者类时,方法通常应该关联于对象的原型,而不是定义到对象的构造器中。原因是这将导致每次构造器被调用时,方法都会被重新赋值一次(也就是,每个对象的创建)。
这是个很典型的例子,学到构造函数和原型的时候总会有提及。

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
  this.getName = function() {
    return this.name;
  };

  this.getMessage = function() {
    return this.message;
  };
}

在上面的代码中,我们并没有利用到闭包的好处,因此可以避免使用闭包。修改成如下:

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
}
MyObject.prototype = {
  getName: function() {
    return this.name;
  },
  getMessage: function() {
    return this.message;
  }
};

但我们不建议重新定义原型。可改成如下例子:

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
}
MyObject.prototype.getName = function() {
  return this.name;
};
MyObject.prototype.getMessage = function() {
  return this.message;
};

以上都是来自MDN的砖块打造,更加详细的内容欢迎同学们去看MDN闭包的文档。


虽然有人说答题不是复制粘贴一下文档就完事了,不过想了想还是把MDN给的示例搬了过来,因为他真的不错。(菜鸡瑟瑟发抖.png)

什么是闭包?闭包的作用是什么?

什么是闭包

Closure是函数有能力记住和访问变量的词法作用域, 在函数本身已经执行完成后。(数据持久性)

闭包出现的原因

由于js引擎的垃圾回收机制, 在执行我们的代码的时候,js维护着一个调用栈。在函数执行完成的时候,由垃圾回收机制去处理这个调用栈(调用栈内包含函数的词法作用域), 要销毁调用栈的时候,发现还存在引用。那么垃圾回机制就不处理它。这就导致这个函数的词法作用域保留了下来,也让该函数具有了数据持久性。有利也有弊,基于垃圾回收机制,如果你的闭包内存有大量数据, 那么它是不会被清除的, 这就需要我们自己手动的去处理它。

闭包的作用

  1. 私有化变量, 封装变化
  2. 构建块级作用域: 关于那道题setTimeout, 应该还有一种答案.虽然看起来比较麻烦,但是它可以跑
console.log('方案3: setTimeout内闭包');
for (let i = 0; i <= 3; i++) {
    setTimeout(((i) => {
        return () => {
            console.log(i);
        }
    })(i), i * 1000);
}
  1. 函数式编程里的偏函数用到了闭包
const addOperator = x => y => x + y;
const add1Operator = addOperator(1);
const add2Operator = addOperator(2);

add1Operator(1); // 2
add2Operator(1); // 3

讲个故事:一对情侣去酒店开房!到了晚上要做就要做该做的事情,嘿嘿嘿的那种。门房禁闭。窗户窗帘拉上,从外面绝对看不到房间内状况。但是万恶的酒店老板是在房间内装了隐形摄像头(闭包)...老板通过摄像头能清楚的看到大战状况...

我敬你是个人才~~~

什么是闭包?

闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包最常用的方式就是在一个函数内部创建另一个函数。

闭包的作用

  1. 私有化变量
function base() {
    let x = 10;
    return {
        count: function() {
            return x++;
        }
    }
}
let obj = base();
console.log(obj.count()); //11
console.log(obj.count()); //12
console.log(obj.count()); //13
  1. 模拟块级作用域
var a = [];
for (var i = 0; i < 10; i++) {
    a[i] = (function(j){
        return function () {
            console.log(j);
        }
    })(i)
}
a[6](); // 6

闭包的缺点

闭包会导致函数的变量一直保存在内存中,过多的闭包可能会导致内存泄漏

闭包(closure) 是指在一个函数有权访问另一个函数作用域中的变量的函数

function box(){
 var a = 10;
 function inner(){
   return a;
 }
 return inner;
}
var outer = box();

闭包的作用

  • 可以读取函数内部的变量
  • 让变量的值 始终保存在内存中
 function f1(){
    var result = new Array();
    for(var i =0;i<10;i++){
             result[i] = function(){
               return i;
      }
   }
  return result
 }

输出结果是10个10
可以改成写

 function f1(){
    var result = new Array();
    for(var i =0;i<10;i++){
             result[i] = function(num){
                  return function(){
                      return num
                 }
      }(i)
   }
  return result
 }

我们没有直接将闭包返回给数组,而是定义了一个匿名函数,将立即执行的结果赋给了数组。这里的匿名函数有个一个参数num,也就是最终的函数要返回的值。在调用这个匿名函数时,我们传入变量i。由于时按值传递的,所以就会将变量i赋值给num,又创建了便返回num的闭包,这样一来,result数组里面的每个函数都有自己num变量的一个副本,所以能到我们预期的结果
符合预期

  • 闭包:闭包是函数和声明该函数的词法环境的组合。函数声明时能够访问的局部变量,在调用时仍然能够访问。闭包可以理解为,定义在一个函数内部的函数。
  • 作用:
    1.能够获取其他函数内部的变量;
    2.让这些变量一直保存在内存中。

闭包: 外部作用域访问内部作用域变量的方法。
作用:使变量一直驻扎在内存中
缺点:导致内存泄露

闭包的概念

闭包是指有权访问另一个 函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。

闭包的作用

  1. 记住了函数所在的词法作用域,使其不被销毁。
  2. 能够访问函数所在词法作用域的变量。
  3. 创建模块(设计私有变量、公有函数等等)。

闭包的应用场景

  1. 函数绑定
function bind(fn, context){
        return function(){
              return fn.apply(context, arguments); 
 };
}

在 bind()中创建了一个闭包,闭包使用 apply()调 用传入的函数,并给 apply()传递 context 对象和参数。注意这里使用的 arguments 对象是内部函 数的,而非 bind()的。当调用返回的函数时,它会在给定环境中执行被传入的函数并给出所有参数。

  1. 函数柯里化
    调用另一个函数并为它传入要柯里化的函数和必要参数。使用一个闭包返回一个函数。
function curry(fn){
        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);
    };
 }

使用闭包的注意事项

由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多,在绝对必要的情况下再考虑使用闭包。虽然像 V8 等优化后的 JavaScript 引擎会尝试回收被闭包占用的内存,但是闭包还是要慎重使用。

闭包指的是能够访问另一作用域的值的能力,常见的闭包就是在一个函数内部创建另一个函数。
作用:延长变量的周期

当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数在所在词法作用域外执行。
闭包的作用:可以创建一个封闭的环境;使变量一直存在于内存中。

### 闭包是将函数内部和函数外部连接起来的桥梁。

### 作用:
1.读取函数内部的变量
2.让这些变量的值始终保持在内存中

闭包闭包就是能够读取其他函数内部变量的函数。在JS中,只有在函数内部的子函数才能读取局部变量,因此可以简单理解成“定义在函数内部的函数”,所以在本质上:闭包就是将函数内部和函数外部连接起来的一个桥梁。

闭包的作用
1、封装私有变量

function Person1() {
       var money = 100;
       this.makeMoney = function () {
           return ++money;
       }
       this.offer = function () {
           return --money;
       }
       return this;
   }
   var person1 = new Person1();
   console.log(person1.makeMoney()) //101
   console.log(person1.makeMoney()) //102
   console.log(person1.makeMoney()) //103
   console.log(person1.offer()) //102

2、实现模块化

 function Person2() {
        var money = 50;
        function makeMoney() {
            return ++money;
        }
        function offer() {
            return --money;
        }
        return {
            makeMoney:makeMoney,
            offer:offer
        };
    }
    var person2 = new Person2();
    console.log(person2.makeMoney()) // 51
    console.log(person2.makeMoney()) // 52
    console.log(person2.makeMoney()) // 53
    console.log(person2.offer()) // 52

3、模拟块级作用域

  for (var i = 0; i < 5; i++) {
            (function (j) {
                setTimeout(function () {
                    console.log(j)
                }, j * 1000)
            })(i)
        }

闭包:闭包就是能够取其他函数内部的变量,在js中,只有在函数内部的子函数才能读取局部变量,因此可以理解成定义函数内部的函数,所以本质上,就是连接内部和外部的桥梁,

闭包的作用:

1.封装私有变量

function mank() {
   var money = 0;
   this.makeMoney = function () {
       return ++money;
   }
   this.offer = function () {
       return --money;
   }
   return this;

}
var mank= new mank();
console.log(mank.makeMoney()) //1

2.实现模块化

function mank() {
var money = 2;
function makeMoney() {
return ++money;
}
function offer() {
return --money;
}
return {
makeMoney:makeMoney,
offer:offer
};
}
var mank= new mank();
console.log(person2.makeMoney()) // 3

3.模拟块级作用域
for (var i = 0; i < 3; i++) {
(function (j) {
setTimeout(function () {
console.log(j)
}, j * 1000)
})(i)
}

总结:闭可能会造成内存的泄露,但还是很长用

闭包
闭包就是在函数中嵌套函数 并返回嵌套函数作为结果

闭包的作用
嵌套函数可以访问外层函数的变量

闭包的场景
只有函数可以产生闭包

闭包的例子
function fn(){

let a =1;

let  addnum = function (){

  a++
}

return addnum;

}
var a1 = fn.addnum()

var a2 = fn.addnum()

var a3 = fn.addnum()

console.log(a1,a2,a3) // 2,3,4

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

(function(k){

  setTimout(fucntion(k){

    console.log(k)

  },k*1000)

})(i)  

}

闭包(Closures):

概念:闭包就是能够读取其他函数内部变量的函数。

最大用处:

  1. 可以读取函数内部的变量
  2. 让这些变量的值始终保持在内存中
  3. 写轮子(反复使用)

弊端:

  1. 占用更多的内存
  2. 不易释放

例子:

闭包

什么是闭包?闭包的作用是什么

###为了保护数据能被获得但不会被改变的这种场景,比如:

function test () {
	var protectData  = 'You can not see me outersize'
	function getProtectData () {
		return protectData
	}
	return getProtectData()
} 
test() // "You can not see me outersize"

###可以封装模块

###实现块级作用域(类似于let)

for (var i = 0; i < 5; i++) {
	setTimeout(function() {
		console.log(i)
	}, 1)
}// 5 5 5 5 5

解决方案一:

for (var i = 0; i < 5; i++) {
    (function(i) {
        // 这里是块级作用域
        setTimeout(function() {
            console.log(i)
        }, 1000);
    })(i);
}// 1 2 3 4 5

解决方案二:

for (let ii = 0; ii < 5; ii++) {
	setTimeout(function() {
		console.log(ii)
	}, 1)
}// 1 2 3 4 5

闭包的确定

内存泄漏
非必要情况少用

什么是闭包?

闭包是指在一个函数有权访问另一个函数作用域中的变量的函数。、

闭包的作用是什么?

能够获取其他函数内部的变量
使变量一直存在于内存中

闭包:
当内部函数 在定义它的作用域 的外部 被引用时,就创建了该内部函数的闭包 ,如果内部函数引用了位于外部函数的变量,当外部函数调用完毕后,这些变量在内存不会被 释放,因为闭包需要它们.
闭包作用:
1.可以读取到其他函数内部的变量
2.可以将变量保存在内存中

(微信名:RUN)

红宝书里面说:“闭包就是指有权访问另一个函数作用域中的变量的函数“。 圣经宝典里面说:”从技术的角度来讲,所有的JavaScript函数都是闭包;它们都是对象,它们都关联到作用域链“。 You dont't know JS say:"当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是当前词法作用域之外执行".

只要存在调用内部函数的可能,js就需要保存被引用的函数。js运行时需要跟踪引用到的这个内部函数的所有变量,一直到最后一个变量废除,js的GC才能回收这些变量的内存空间。

作用:

  1. 读取函数内部的变量
  2. 让这些变量值始终保存在内存中

我认同圣经里说的,因为闭包并不是JavaScript的概念,JavaScript标准里从来没提过闭包。从闭包的古典定义里(带有一系列信息的λ表达式)可以发现闭包就是带了执行环境的函数。而JavaScript中函数正好复合这个定义,它的环境部分就是函数的词法作用域