目录
但是上述代码运行结果为10,需求并没有被实现 因为在获取到变量之前,循环已经执行完毕解决方案
通过js作用域的学习,我们可以通过内部作用域可以通过作用域链访问到定义在外部作用域的变量
,但引发一个问题,是否可以通过作用域链实现外部作用域访问到内部作用域的值,当然不可以
但是我们以后将通过什么方式来实现外部作用域访问定义在内部作用域的变量
所以es5引出闭包的概念
给大家看一个最基本的闭包
var a=123
function fn1(){
console.log(a);
var b=234
function fn2(){
console.log(b);
}
return fn2
}
var result=fn1();
result()
此段代码中fn2函数就是一个闭包
我们可以观察到fn2是定义另外一个函数内部的函数,在外部作用域访问b变量就可以实现出来
本质上来收闭包就是函数内部和函数外部建立的一所桥梁
以上就是我们关于闭包的一些基本的理解
下文我们将重点研究闭包的拓展
在实际开发中的应用以及场景 拓展和特点
1.闭包的一些简单应用
1.1用闭包手写一个计数器
function start(){
var num=0
function zi(){
return ++num
}
return zi
}
var result1=start()
result1()
有人可能会好奇:为什么写一个计数器不要采用这种型式而不是下面这种
var result1=start()
result1()
function stat(){
var num=0
++num
return num
}
stat()
这种形势下,当stat函数没执行一次或者n次,输出都为1,因为每一次执行完毕之后,变量num都会在内存中不被保留,反之通过闭包手写计数器时,变量num会一直保留在内存中,所以,以实现累加效果,这就是一个闭包函数的应用
在实际的运行环境中,result1这个变量在执行完毕之后,result1这个变量会在内存中,则start函数也会在内存中,然后num变量也会一直在内存中
但是。。。。这种形式下会导致内存泄露问题,这就是一个闭包函数的缺点
1.2闭包能够封装对象的私有属性和方法
function Person(name){
//私有属性
var age;
//私有方法
function setage(n){
age=n
}
function getage(){
return age;
}
return {
name:name,
setage:setage,
getage:getage
}
}
var p1=Person('mjj')
2.闭包的注意点
2.1
使用闭包使得函数中的变量始终在内存中,内存消耗很大,所以不能滥用闭包,否则会导致页面的性能问题
2.2
参考上述代码,每个父函数调用完成之后,都会形成新的闭包,父函数中的变量始终在内存中,相当于缓存,小心内存消耗问题
总结函数嵌套,访问所在的作用域,在作用域外被调用
通过以上的学习,我们了解到两种闭包的场景,但在js的世界中,闭包的场景及其众多,下面我们来认识立即执行函数中闭包的相关问题
3.立即执行函数及其闭包
3.1关于立即执行函数
(function(){})();
!(function(){}());
以上立即执行函数的两种写法
但是我们常用的是第二种写法
立即执行函数也叫闭包,可以封装私有的属性,同时可以减少对全局变量的污染
实例需求
将数组的每一项循环遍历出来
function foo(){
var arr=[];
for(var i=0;i<10;i++){
arr[i]=function(){
return i
}
return arr
}
}
var bar =foo()
但是上述代码运行结果为10,需求并没有被实现 因为在获取到变量之前,循环已经执行完毕
解决方案
使用闭包解决循环中变量问题,就是想办法把变量缓存在内存中,每次执行的时候从内存种获取
function foo(){
var arr=[];
for(var i=0;i<10;i++){
(function(n){
1 arr[n]=function(){
return n
}
})(i)
}
var bar =foo()
核心思想就是,将i变为一个私有变量然后保存在内存中,这样就可以实现需求,我们可以观察到当标记为1的匿名函数为一个闭包时,i作为立即执行函数的私有变量,然后作为实参传入闭包,供闭包使用
function foo(){
var arr=[];
for(var i=0;i<10;i++){
arr[i]=(function(n){
//此处为一个闭包
return function (){
return n
}
}(i)
)
}
此时 i还是作为立即执行函数的私有变量,然后作为形参传递进去
4.闭包的十大应用场景
闭包的应用的场景我觉得也是一个重点,最近在学习react种,闭包就被应用到了,react hooks种许多内置文件就时用闭包实现了,且都利用了闭包种变量缓存这一特点,所以说掌握闭包得应用场景还是很重要的
4.1返回值
最常见的一种场景
var fn=function (){
var name ='mjj';
return function (){
return name;
}
}
var func=fn()
console.log(func());
这个不做过多介绍
4.2函数赋值
在全局种定义一个全局变量 ,然后将闭包函数赋值给这个变量
var fn2;
var fn=function (){
var name ='mjj'
var a =function (){
return name
}
fn2=a
}
fn()
console.log(fn2());
4.3函数参数
function fn2(f){
console.log(f());
}
function fn(){
var name='mjj';
var a=function (){
return name
}
fn2(a)
}
fn()
4.4循环赋值
参考上文
4.5简单迭代器
function setup(arr){
var i=0
return function(){
return arr[i++]
}
}
var next=setup(['alex','mjj','阿黄'])
4.6区分首次
var first =(function (){
var list =[]
return function(id){
if(list.indexOf(id)>=0){
return false
}else{
list.push(id)
return true
}
}
})()
当每次获取一个函数的id
先到这儿之后再补充