笔者并非大神,只是一个在校的大三学生。开始写深刻理解系列是为了给js的一些重难点知识进行梳理,而不是每次面试以前都将这些知识从新理解一遍。有理解的不对的,请赐教!事不宜迟,咱们开始吧。javascript
闭包是函数!(废话)闭包仍是一个能够访问函数中变量的函数。java
function who(){ let name='clong'; function print(){ return name; } return print; } let boy=who(); let myName=boy(); console.log(myName);//'clong'
开始的定义可能会令你感受晦涩难懂,看了上面的例子咱们一块儿来理解一下。git
下面咱们来分析一下上面的栗子。github
有了上面的栗子,咱们来看看下面这个栗子:面试
function createCounter() { let counter = 0 const myFunction = function() { counter = counter + 1 return counter } return myFunction } const increment = createCounter() const c1 = increment() const c2 = increment() const c3 = increment() console.log('example increment', c1, c2, c3)//1,2,3
思考一下,答案与你认为的同样吗?是否是觉得是1,1,1呢?先不要急,咱们再来看看下面这个栗子。闭包
var makeCounter = function() { var privateCounter = 0; function changeBy(val) { privateCounter += val; } return { increment: function() { changeBy(1); }, decrement: function() { changeBy(-1); }, value: function() { return privateCounter; } } }; var Counter1 = makeCounter(); var Counter2 = makeCounter(); console.log(Counter1===Counter2); console.log(Counter1.value()); /* logs 0 */ Counter1.increment(); Counter1.increment(); console.log(Counter1.value()); /* logs 2 */ Counter1.decrement(); console.log(Counter1.value()); /* logs 1 */ console.log(Counter2.value()); /* logs 0 */
看看上面的栗子,你会不会疑惑?本质上都是调用的私有函数的方法,为何Counter1和Counter2的privateCounter就会彻底不同呢?函数
笔者查看了不少资料,别人总结的要么就是将mdn上的解释一贴,要么就是含糊其辞。性能
请注意两个计数器 counter1 和 counter2 是如何维护它们各自的独立性的。每一个闭包都是引用本身词法做用域内的变量 privateCounter 。每次调用其中一个计数器时,经过改变这个变量的值,会改变这个闭包的词法环境。然而在一个闭包内对变量的修改,不会影响到另一个闭包中的变量。————MDN
那么为何对一个闭包的变量的改变不会影响到另外一个闭包中的变量呢?我思考了好久,最后这样解释给本身听:this
前一个栗子中,咱们的increment保存的是myFunction的引用和他的闭包(important:函数在建立的时候就会造成本身的做用域链)。了解过闭包的应该都有保存在内存中这个概念,那么咱们这里没得操做都是直接对闭包的操做,价值做用域的执行顺序(闭包=>父级=>...),每次都是从闭包中获取,而且将修改的值保存在内存中,天然是1,2,3!code
那么后面一个栗子呢?我先姑且解释看看(有不对的但愿大牛能够指出),函数中的变量都是私有的(包括函数),第二个栗子返回的是一个对象,而后咱们后面的操做都是基于这个对象的属性的操做,间接操做了内部的私有方法并获取了内部的值。那么,回想一下new一个对象发生了什么?
这个栗子不是正好跟上面的操做相似吗?若是仍是不明白,咱们假设makeCounter是一个Array对象,里面的private和changeBy是length和push内部实现原理,返回一个新对象,而且给了你一些接口,而这个接口正好有push,使你能够进行push操做,且仅限于该对象的私有属性的方式。那么实例与实例的私有属性或方法共有吗?固然不!神奇的利用闭包就实现了数据的私有和封装了
通过了上面的分析,咱们大概能够了解到闭包的一些用处了吧。
这些也是耳熟能详了!
MDN/JS/闭包
Understand JavaScript Closures With Ease
I never understood JavaScript closures