Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[js] 第14天 什么是闭包?优缺点分别是什么? #44

Open
haizhilin2013 opened this issue Apr 29, 2019 · 26 comments
Open

[js] 第14天 什么是闭包?优缺点分别是什么? #44

haizhilin2013 opened this issue Apr 29, 2019 · 26 comments
Labels
js JavaScript

Comments

@haizhilin2013
Copy link
Collaborator

第14天 什么是闭包?优缺点分别是什么?

@haizhilin2013 haizhilin2013 added the js JavaScript label Apr 29, 2019
@myprelude
Copy link

(fucntion(){

})()
function(){
  var a = 0;
 return function(){
   return a++
 }
}

上面就是闭包,有独立的作用域,且作用域的变量不会在程序中释放

@Damon99999
Copy link

closure:关闭
关闭变量或者说是隐藏一个变量
我们函数套函数其实相当于形成了一个局部作用域,就达到了隐藏的目的
仅此而已

@AricZhu
Copy link

AricZhu commented Jun 24, 2019

  1. 首先,在函数外部是无法访问函数内部的变量的。
  2. 为了解决上述问题,则引入了闭包。简单来说就是为了能访问函数A内部的变量值,需要在函数A中定义一个其他的函数B,并且将B返回给外部变量,那么外部变量就可以通过B来访问到函数A中的变量了。这就是闭包。
  3. 闭包方便访问函数内部的变量,但同时也会导致原来函数A中的变量无法及时销毁,导致内存占用过高。并且如果没有及时销毁的话,也存在内存泄露问题。

@Vi-jay
Copy link

Vi-jay commented Jul 26, 2019

闭包:在局部作用域引用上层作用域(非全局)的变量
优点:防止变量污染作用域
缺点:不释放则会导致内存泄漏

@Konata9
Copy link

Konata9 commented Jul 27, 2019

闭包是可以访问另一个函数作用域的函数。由于 javascript 的特性,外层的函数无法访问内部函数的变量;而内部函数可以访问外部函数的变量(即作用域链)。

function a(){
	var b = 1;
	var c = 2;
	// 这个函数就是个闭包,可以访问外层 a 函数的变量
	return function(){
		var d = 3;
		return b + c + d;
	}
}

var e = a();
console.log(e());

因此,使用闭包可以隐藏变量以及防止变量被篡改和作用域的污染,从而实现封装。
而缺点就是由于保留了作用域链,会增加内存的开销。因此需要注意内存的使用,并且防止内存泄露的问题。

@hsiaosiyuan0
Copy link

https://cnodejs.org/topic/5d39c5259969a529571d73a8

@EarthShakers
Copy link

https://cnodejs.org/topic/5d39c5259969a529571d73a8

感谢大佬的分享,讲的十分透彻。

@lizhesystem
Copy link

闭包的定义:从外部访问或者操作函数内部变量的的方式,缓存数据,延长作用域链(JS是函数作用域)

例子:定义了一个内部变量,但是不想使这些变量不能被外部随意修改,同时又可以通过指定的函数接口来操作来访问,闭包的作用常常用来「间接访问一个变量」。换句话说,「隐藏一个变量」

缺点:函数中的变量不能及时的释放

function Foo(){
 var name = "fooname";  //需要从外部访问这些变量
 var age = 12;
  
 this.getFoo = function(){  //设置访问方法
  return name;
 }
  
 this.setFoo = function(){
  return age;
 }
 this.xgFoo = function(new){
  name = new;
 }
}

var foo = new Foo();
foo.getFoo();  //访问name变量。
foo.xgFoo("liz") //从外部修改nage变量

@qiqingfu
Copy link

qiqingfu commented Apr 13, 2020

当函数能够记住并访问所在的词法作用域,即使函数是在当时词法作用域之外执行,这是就产生了闭包。

词法作用域是变量或函数声明时,在词法解析阶段所在的作用域。

function foo() {
  var a = 2;

  function bar() {
    console.log(a)
  }

  return bar
}

var baz = foo()

bar() // 2
  1. 编译器进行词法解析阶段就已经确定 foo 函数的作用域内有 abar 标识符。
  2. foo 函数执行,将 bar 函数的引用返回
  3. 在全局作用域调用 bar 函数,也就是在 bar 函数词法作用域(foo) 之外调用。按理说 foo 函数调用完结束后就应该被销毁了。但是闭包能够让 bar 函数一直引用着它在词法阶段所在的作用域 foo,这个引用就是闭包。所以可以正常访问变量 a

这个 bar 函数在定义的词法作用域以外的地方被调用。闭包使得函数能够继续访问定义时的词法作用域。

无论通过何种手段将内部函数传递到所在的词法作用域以外,它都会持有对原始定义作用域的引用,无论何时执行这个函数都会使用闭包。

@larry0442
Copy link

定义

看黑体字:
函数wrapper_func内 返回一个函数inner_func, 外部通过inner_func可以访问wrapper_func函数内变量(作用域链)。

用法

函数返回函数,形成局部作用域

优点

局部作用域,防止变量污染

缺点

内存泄露

面试官会问的在那里使用:

命名空间/for循环取第i个处理为什么返回同一个i值(可以搜一下,老面试题了)

@blueRoach
Copy link

闭包是一个函数,这个函数可以访问另一个函数的变量。(当你创建一个函数时你就创建了一个闭包)
优点:由于闭包里可以访问外部变量,但是外部不能访问闭包里的变量,所以可以保护一些重要的不能被修改的变量。
缺点:在老IE6使用闭包可能会造成内存泄漏

@giggleCYT
Copy link

闭包就是声明在函数内部的函数(或者是可以访问外部函数变量的函数)
优点:希望一个变量长期存储在内存中,避免全局变量的污染,私有成员的存在
缺点:会导致内存占量过高,容易造成内存泄露

@waterkitten
Copy link

函数中裹着函数就产生闭包,父函数访问子函数就是借用闭包的作用
子函数访问父函数就是顺着作用域链
有点类似vue框架的父能传参给子组件,而子组件只能this.emit才行

@laboonly
Copy link

第14天 什么是闭包?优缺点分别是什么?

函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在 JavaScript 中,每当函数被创建,就会在函数生成时生成闭包。

@MrZ2019
Copy link

MrZ2019 commented Sep 10, 2020

闭包:在局部作用域引用上层作用域(非全局)的变量
优点:防止变量污染作用域
缺点:不释放则会导致内存泄漏

@xiezhenghua123
Copy link

从函数外部访问到函数内部的变量,函数内部的变量的作用域不会被释放,通常从函数内部返回一个函数。
缺点:会导致内存泄漏

@378406712
Copy link

378406712 commented Apr 27, 2021

简单说就是函数套函数,函数外部可以访问到内部的变量,
优点:防止全局变量污染
缺点:可能会导致内存泄漏(ie

@amikly
Copy link

amikly commented Nov 2, 2021

概念

当一个函数能够访问和操作另一个函数作用域中的变量时,就构成了一个闭包(closure)

function f1(){
   var n=999;
   function f2(){
      alert(n); // 999
   }
}
//函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的

上面代码中的f2函数,就是闭包

由于在javascript中,只有函数内部的子函数才能读取局部变量,所以说,闭包可以简单理解成“定义在一个函数内部的函数。

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

优点:防止变量污染作用域

缺点:不释放则会导致内存泄漏

用途

  • 读取函数内部的变量
  • 让函数内部的变量的值始终保持在内存中,不会在父函数调用后被自动清除

注意

  • 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
  • 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值

@tk12138
Copy link

tk12138 commented Nov 17, 2021

要理解闭包,首先要理解JS的变量作用域。变量的作用域有两种:全局变量和局部变量。JS语言的特别之处在于:函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。那么如何从外部读取函数内部的局部变量?可以在函数内部再定义一个函数,如下所示:
1.function f1(){
2.    var n=999;
3.    function f2(){
4.        alert(n); // 999
5.    }
6.}
在上面的代码中,函数f2被包含在函数f1内部,这时f1内部的局部变量对f2都是可见的。但是反过来就不行。既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,就可以在f1外部读取其内部的变量,故而f2函数就是闭包。因此闭包可以理解为定义在一个函数内部的函数。
闭包的作用:可以读取函数内部的变量;让这些变量的值始终保持在内存中,不会自动清除。
注意点:由于闭包会使函数中的变量都被保存在内存中,内存消耗较大,所以不能滥用闭包,否则会造成网页的性能问题。解决方法是:在退出函数之前,将不使用的局部变量全部删除;闭包会在函数外部,改变夫函数内部变量的值。

@github-cxtan
Copy link

要理解闭包,首先要理解javascript的特殊的变量作用域。
变量的作用域无非就两种:全局变量和局部变量。
优点:防止污染作用域
缺点:需要手动置null,不然会内存泄漏

@yxllovewq
Copy link

yxllovewq commented Mar 8, 2022

作用域链:只能访问自身或外层作用域的变量。
闭包:可以访问函数内部变量的函数。
方式:在函数a中手动返回一个函数b,该函数b包含了函数a中的变量。

function a(){
  let n = 1;
  return () => n;
}
a()()  // 可以获取到a函数中声明的变量n

作用:

  1. 保存、隐藏变量、作为私有变量
  2. 避免污染全局环境
    缺点:由于外部可以访问到函数内部的变量,因此函数在执行完成后,函数上下文环境依然存在,闭包过多,会导致内存不足。

@xiaoqiangz
Copy link

闭包: 当一个函数能访问和操作另一个函数作用域的变量时,此时就形成了闭包
优点: 避免污染全局环境
缺点:由于外部可以访问到函数内部变量,因为函数执行完成后,函数没有被销毁,闭包过多会导致内存泄露。

@WangXi01
Copy link

一个函数可以访问另一个函数内的变量,当这个函数被运行时,就形成了一个闭包,因为这个变量因为被引用着,所以即使执行完毕了也不会被回收掉。

@HoseaGuo
Copy link

HoseaGuo commented Aug 11, 2022

来自mdn的解析:闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。

就是每一个函数都是一个闭包

闭包是一个函数和它周围环境(词法环境)的引用的组合。

所以每一个函数可以形成一个闭包。

函数局部作用域,可以含有一些私有变量、私有函数(外部不能直接访问),结合函数的闭包,使得函数以外也可以通过函数内部的抛出的函数访问函数的私有变量和私有函数。

function outerFn(){
  // 私有变量,outerFn函数外不能直接访问
  var _name = 'private name';
  // 私有函数,outerFn函数外不能直接访问
  function _fn(){
    console.log("trigger private function")
  }
  // 返回一个方法,以供外部可以访问到outerFn的私有变量、函数
  return function(){ // 返回的这个函数,可以访问_name、_fn()
    console.log(_name)
    _fn();
  }
}

let fn = outerFn();
fn();

for循环问题

html文件

<ul>
  <li>xxxxxxxxxxx</li>
  <li>xxxxxxxxxxx</li>
  <li>xxxxxxxxxxx</li>
  <li>xxxxxxxxxxx</li>
</ul>
var liElements = document.getElementsByTagName('li');
for(var i=0; i< liElements.length; i++){
  liElements[i].onclick = function(){
    console.log(i); // 因为 变量i 是公用一个词法环境,所以最终输出的都一样,都输出 4
  }
}

可以用新的函数来隔开不同的i,使得获取的i在不同的词法环境

var liElements = document.getElementsByTagName('li');
for(var i=0; i< liElements.length; i++){  
  liElements[i].onclick = (function(i){ // 利用自执行匿名函数,给每一个元素的onclick事件分隔开了不同值的i
    return function(){
      console.log(i); // 分别输出 0、1、2、3
    }
  })(i)
}
var liElements = document.getElementsByTagName('li');
Array.prototype.forEach.call(liElements, function(item, i){  // 利用匿名函数,给每一个元素的onclick事件分隔开了不同值的i
  liElements[i].onclick = function () {
    console.log(i)
  }
})

或者使用ES2015 引入的 let 关键词

var liElements = document.getElementsByTagName('li');
for (let i = 0; i < liElements.length; i++) {
  liElements[i].onclick = function () {
    console.log(i); // 分别输出 0、1、2、3
  }
}

@wuder-jie
Copy link

  • 闭包:函数可以访问外部作用域的变量,就形成了闭包。
  • 作用:有保护和保存的作用。保护函数内部变量不被外部访问和修改,如果外部需要访问,可以返回出去。保存:保存变量的引用,不被销毁。

@lili-0923
Copy link

闭包就可以在全局函数里面操作另一个作用域的局部变量!
优点:私有变量
缺点:造成内存泄漏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js JavaScript
Projects
None yet
Development

No branches or pull requests