这三儿绝对面试必问的东西吧 如果你单单是根据书上的概念,自己冥想,对于前端基础不太好(比如我)的人来说,光是一个原型链就可以把你绕的崩溃。
今天这篇文章 就让我们彻底揭开闭包的真面目把!
在面试的时候 常常面试官会问到:“来,谈谈闭包把” “你知道js的闭包把?说说看呢” “谈一谈你对闭包的理解呢?”
这时候我们可能想:这也太简单了把 然后随口一句 闭包就是一个能够访问其他函数内部作用域变量的函数,闭包会造成内存泄漏…
那如果面试官接着问你为什么闭包能够访问其他函数内部作用域变量?为什么闭包会造成内存泄漏?
首先来看看书上是怎么说的:
1.闭包是指有权访问另一个函数作用域中的变量的函数
2.闭包可以使函数的作用域相互关联起来,函数内部的变量可以保存在其他函数作用域内
闭包可以使函数的作用域相互关联起来?那什么是作用域?作用域链?你得给面试官解释清楚吧?
js就两个作用域:全局作用域和局部作用域(创建一个函数,函数内部就是一个局部作用域)
全局作用域和局部作用域中变量的访问权限,其实是由作用域链决定的。
每次进入一个新的执行环境,都会创建一个用于搜索变量和函数的作用域链。作用域链是函数被创建的作用域中对象的集合。作用域链的最前端始终是当前执行的代码所在环境的变量对象(如果该环境是函数,则将其活动对象作为变量对象),下一个变量对象来自包含环境(包含当前执行环境的环境),下一个变量对象来自包含环境的包含环境,依次往上,直到全局执行环境的变量对象。全局执行环境的变量对象始终是作用域链中的最后一个对象。
好了,这描述看似很绕,其实把作用域链就可以当成一条链子,这不过这个链子在程序中是以一个集合存在的,我们可以形象的就把它看成垂直的一条链子,这个链子从下往上挂着一个个的变量对象,这个变量对象就当成当前作用域下所有变量+arguments装成的一个盒子,最下面挂着当前你执行的代码所在环境中这个作用域里变量聚集成的一个盒子,其上面挂着包含着当前环境的环境里变量聚集成的一个盒子,再往上依次。。 我们在查找变量时,顺着这根链子,先查找最下面的也就是当前执行环境里的这个盒子,把变量都翻出来看有没有,没有再接着往上爬着查找,直到爬到最上面爬到全局环境来了,如果这里没有,那不好意思,那真就没有了。
而且这根链子很奇怪 ,只能从下往上找(也就是内部能够访问外部作用域里的变量) ,你要从上往下,那不好意思,拒绝❌。一个局部作用域能访问另外一个局部作用域的变量吗?你想从这根链子飞到另外一根链子上去看看对面都有些啥东西?不好意思,犯规了,拒绝。
好了总结一下:1.函数的局部环境可以访问函数作用域中的变量和函数,也可以访问其父环境,乃至全局环境中的变量和环境
2.全局环境只能访问全局环境中定义的变量和函数,不能直接访问局部环境中的任何数据
3.两个同级函数作用域变量不能互相访问
好了 为什么闭包能够访问其他函数内部作用域变量? 就是因为作用域链吧 函数可以访问其自己局部作用域的变量,也可以访问包含它的外部的作用域里的变量。
下面看个函数
function f() {
var name=“航”;
function child() {
console.log(name);
}
return child;
}
var person = f();
person();//打印航
上面就是一个标准的闭包,内部child函数引用了其外部函数f()里的变量name,外部函数f()最终返回了child() var person=f();将child函数赋给变量person,最后person()执行这个函数,由于返回的这个函数一直保存着对name的引用,所以变量name的内存不会释放,这样,在全局就能访问到函数内部的局部变量了!即打破了作用域链。
那为什么我把内部一个引用了其外部作用域变量的函数返回,用一个变量保存起来再执行,这个变量内存就不释放了?不是通常一个函数执行完毕其作用域和作用域里的变量都会被销毁吗?
js垃圾回收机制说道:我对于正处于环境中的标识符以及环境中的标识符引用的变量或函数,我不清除,嘿嘿,傻了吧?
这下,问题都说的通了吧?当然,这也只是我自己的一个小小的总结。
其实总结一下 要解释闭包 我会这么给面试官说:
闭包是JS里面非常经典也很常用的一种技术,我给面试官您简单说一下吧,由于函数在创建时都会在其内部生成一个局部作用域,其作用域和包含着它的环境的作用域之间会形成一条作用域链,在查找变量时,先在作用域最前端也就是其自身内部作用域下查看该变量,如果不存在,则顺着作用域链向上查找,直到查找到全局环境中为止,闭包自身是一个函数,其内部引用了它外部环境中的变量,最后在外部包含它的函数中作为返回值返回,由于js垃圾回收机制对于环境中的标识符以及环境中的标识符引用的变量或函数不清除,就使得我们可以在全局变量中通过返回的这个闭包函数来访问一个函数内部的局部变量。
当然其中内部还有更加深的东西,包括其编译器的过程也有涉及,要谈的话可以谈的非常复杂,这里如果这样子答的话如果再叫具体谈一下作用域链,也可以根据上面我总结的一些东西简单解释下,内存泄漏啊因为垃圾回收机制也能简单解释解释,如果再要挖底层,那少年你确实运气太差了!!!