javascript闭包立即执行函数(代码片段)

白瑕 白瑕     2022-12-17     125

关键词:

JavaScript闭包


# 前言-什么是闭包函数 闭包函数是声明在另一个函数内的函数,是被嵌套在父函数内部的子函数,在《JS高级程序设计-第3版》中对闭包解释是:"闭包是指有权访问另外一个函数作用域中的变量的函数." 闭包函数可以访问[包裹其的函数]内的各种参数和变量,即便外部函数已经执行完毕.(至于为什么请看下文).

一、为什么要闭包

  1. 使外部得以访问函数内部的变量;
  2. 避免全局变量的使用,防止全局变量污染(匿名函数);
  3. 让某些关键变量得以常驻内存,免于被回收销毁(闭包函数);

二、让某些变量得以常驻内存

我们需要将立即执行函数与闭包结合;
我们都知道JavaScript是自带垃圾回收机制的,对于函数来说,在其执行完毕后会被垃圾回收机制回收来进行内存释放,函数内部的局部对象(各种变量之类)也会被连同销毁使内存中仅仅保存全局作用域.

1.原理

前言说到闭包函数就是一个嵌套在父函数里面并且有使用父函数变量的子函数, 闭包函数的执行必定依赖于父函数提供的数据,但要是调用闭包函数时父函数已经被销毁,闭包函数怎么执行呢?
没法执行,因为闭包函数所依赖的变量也都被销毁,总不能因为要执行闭包函数再把父函数提出来,不太合理;

所以不能就这么回收掉,但是保存整个父函数又有点离谱,所以JavaScript垃圾回收机制只会保存闭包函数在父函数中所依赖到的变量这些被保存起来的变量不会被内存回收器回收,直到确认子函数不会再被调用(子函数被删除或者失去指针)为止;

类比一下,如果你学过webpack的话,应该会知道webpack在打包一个文件的时候会把这个文件依赖的所有文件一起打包,就是为了防止使用的时候出问题,垃圾回收机制是在删减的时候留下需要的,weboack是在打包的时候加上需要的.

2.Why 立即执行函数?

我想探讨一下为什么推荐用立即执行函数来配合闭包进行变量保存…
一开始我猜为了在闭包函数保存完需要的变量后父函数能被及时回收释放内存,才采用了匿名立即执行函数来作为闭包函数的父函数.因为立即执行函数自我回调执行完成后会被立即销毁回收,用一次就释放,节约内存(但因为销毁快,外界无法引用其内部的变量)
后来看到了一个例子,作者将使用了立即执行函数的闭包和没有使用立即执行函数的闭包进行了比较,让我改变了想法:

//例1,这个例子中没有使用立即执行函数;
function createFunction() 
    var Array = [];
    for( var i = 0; i<10; i++) 
    //将函数赋值给每个数组元素;
        Array[i] = function() 
            return i;
        ;
    
    return Array;


var aa = createFunction();
console.log(aa[0]()); //10
console.log(aa[1]()); //10

由于作用域链的配置机制,因为每个函数的作用域链中保存的都是createFunctions()的活动对象,所以每个函数引用的都是活动对象中的同一个变量 i。
(活动对象: 在JavaScript中,当一个函数被创建时最后一步便是活动对象推入作用域链,函数中访问一个变量时会从作用域链中搜索具有相应名字的变量,函数执行完后局部活动对象会被销毁,活动对象中包含了参数列表和arguments对象等属性. 活动对象包含变量对象所有的属性)
当createFunctions() 函数执行结束返回后,变量 i 的值就已经固定为10,而每个函数保存的变量对象里的 i 都出自createFunctions()的活动对象,每个函数拿到的 i 都是出自同一个活动对象的,都一样,所以最后不论输出哪个数组元素得到的都是10.
即说明了闭包中所保存的是整个活动对象,而不是某个具体的变量,这种机制并不是我们想要的,我们希望它能把每个变量单独保存下来,所以就有了能解决这个问题的,使用了立即执行函数的例子,即例2:

function createFunction() 
    var result = new Array();
    for( var i = 0; i<10; i++) 
    
        result[i] = function(num) 
        //每接收一个num就会创建新的一个函数作用域;
            return function() 
            //在每个作用域的内部创建并返回一个返回num的闭包函数
                return num;
            ;
        (i);
     //变量i的当前值会作为实参赋值给上面的形参num;
     
    
    return result;

//在外部使用函数内变量;
var bb = createFunction();
alert(bb[0]()); //0
alert(bb[1]()); //1

闭包函数依赖到了外部立即执行函数的num,所以num会连同闭包函数被保存下来免于销毁,这样result[ ]中被赋值进去的每个函数都能返回一个自己的num,我们的目的就能达到了,完成这一目标的关键就是使用了立即执行函数.

这个闭包函数的父函数函数每接收一个num就会创建新的一个函数作用域(见例3),作用域中传入i后,变量i的当前值会作为实参赋值给上面的形参num,而在当前每个作用域的内部,又创建并返回了一个返回num的闭包函数。这样一来传入每个函数作用域中闭包函数的num就是不同的了.如此类推,被赋值进入result数组中的每个函数作用域都有一个自己num(其实是时num副本),可以返回各自不同的数值了.

for(var i = 0; i < 5; i++) 
  abc(i);
;

function abc(i) 
  setTimeout(function() 
     console.log(i);			// 0 1 2 3 4 
  , 200); 

//这里就相当于创建了5个函数作用域;

可见立即执行函数在保存变量时泛用性比普通函数强;

三、让外部得以访问函数内变量

外部访问函数内变量跟立即执行函数没什么必然关系,不使用立即执行函数也可以进行保存,上面说到的结合立即执行函数的写法只是针对某些特殊情况下无法依据需求保存变量的问题,我们不得不承认立即执行函数泛用性好一些.

在外部调用父函数即可拿到闭包函数内的变量;

四、立即执行函数

刚学到的,单独开一篇感觉也没必要,正好这里用到了就写下来吧…

//这两种写法是会报错的;
(function() 
//函数体;
 )(); 

function() 
//函数体;
 ();

JavaScript引擎先看到了你的"function"关键字,然后就开始以函数声明标准规范你后续的代码,最终JavaScript引擎发现你用一个小括号结束了你的函数,它觉得这是错的.
我们不能否定它判定的规则,人家认为写了function就是要声明函数,那我们就不要上来直接写function了:

var myFunction = function () 
                   /* 函数体 */ 
                 ();
var myObj = 
    myFunction: function () 
                  /* 函数体 */ 
                ();

让JavaScript引擎先看到小括号而不是function关键字,它就会觉得你在写函数表达式,也就判定为合理了;


总结

比较重要的是闭包会造成内存泄漏.闭包会把一些东西永驻保存下来,而且前面提到的它所依赖的东西都不会被销毁,自己的局部活动对象和依赖到的活动对象都会被包含到它自己的作用域链里,所以它的体量往往是比普通函数大上老些;

javascript学习-46.立即执行函数(代码片段)

前言立即执行函数有以下作用创建一个独立作用域,这个作用域里面的变量,外部访问不到,避免变量污染。闭包和私有数据使用语法有两种写法//第一种:用括号把整个函数定义和括号调用包裹起来(function()//函... 查看详情

javascript闭包和立即执行函数的作用

一、闭包——closure  先看一个闭包的例子。我们想实现一个计数器,最简单的方法就是定义一个全局变量,计数的时候将其加1。但是全局变量有风险,哪里都有可能不小心改掉它。那局部变量呢,它只在函数内部有效,函数... 查看详情

作用域闭包立即执行函数(代码片段)

一、作用域(Scope)        [[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合。即作用域决定了代码区块中变量和其他资源的可见性。1、全局作用域        在外面定义的函数、变量,没有定义,却... 查看详情

javascript中的立即执行函数(代码片段)

javascript中的立即执行函数$(function()  alert();())Highcharts的中的series:[  name:‘今日在线人数‘,  color:‘pink‘,  data:(function()    )())]#执行效果一样$(document).ready(function()console.log("ready!"););和$(function( 查看详情

javascript作用域和闭包(代码片段)

JavaScript中的作用域指的是变量和函数的可访问范围。JavaScript中,闭包是一个函数对象,它可以访问定义该函数的作用域里的变量,即使函数已经返回。闭包的特点是,它可以在其相关环境不存在时保留变量。闭包可以被保存到... 查看详情

深入理解javascript中的立即执行函数(function()…)()(代码片段)

javascript和其他编程语言相比比较随意,所以javascript代码中充满各种奇葩的写法,有时雾里看花,当然,能理解各型各色的写法也是对javascript语言特性更进一步的深入理解。(function()…)()和(function()…())是两种javascript立即... 查看详情

javascript中的立即执行函数(代码片段)

通常我们声明一个函数有以下几种方式://声明函数f1functionf1()console.log("f1");//通过()来调用此函数f1();//一个匿名函数的函数表达式,被赋值给变量f2:varf2=function()console.log("f2");//通过()来调用此函数f2();//一个... 查看详情

闭包和立即执行函数

...,我会持续更新!   一直没搞清楚立即执行函数和闭包之间的关系,总结一下:闭包有很多种理解:访问不到内部作用域,函数就是这样,所以函数就是闭包;闭包还有一种理解:通过把函数内部的变量和方法返回出来,... 查看详情

闭包的概念与不闭包的区别(javascript)(代码片段)

闭包的概念函数执行完后,其作用域就会被清理,局部变量会被回收。如果函数内声明了子函数,且该子函数暴露给全局作用域导致其一直无法被回收。由于子函数可以访问上级作用域中的变量,导致即使上级函... 查看详情

闭包的概念与不闭包的区别(javascript)(代码片段)

闭包的概念函数执行完后,其作用域就会被清理,局部变量会被回收。如果函数内声明了子函数,且该子函数暴露给全局作用域导致其一直无法被回收。由于子函数可以访问上级作用域中的变量,导致即使上级函... 查看详情

闭包的理解(代码片段)

1、什么是闭包?闭包就是指有权访问另一个函数作用域中变量的函数,通俗点讲闭包就是能够读取其他函数变量的函数。常见的构造方法,是在一个函数内部定义另外一个函数。内部函数可以引用外层的参数和变量;参数和变... 查看详情

javascript回调函数属于闭包?(代码片段)

JavaScript回调函数属于闭包?JavaScript回调函数属于闭包?回调函数本身不一定属于闭包,但是在某些情况下,它们可能会涉及闭包。回调函数通常是指在异步操作完成时执行的函数。它们在JavaScript中被广泛使用,例如在处理AJAX... 查看详情

javascript立即执行函数的两种写法(代码片段)

(function(str)console.log(str+'欢迎你~');)('行步至春深');(function(str)console.log(str+'欢迎你~');('行路易知难'));可以看到,每种写法都比平常多出两个小括号,其中一个可以看作是调用,里面装参 查看详情

记录闭包和立即执行函数

闭包:http://www.runoob.com/js/js-function-closures.html 立即执行函数:IIFE(ImmediatelyInvokedFunctionExpression)http://benalman.com/news/2010/11/immediately-invoked-function-expression/#iife 查看详情

通过javascript执行机制去学习闭包,执行上下文,作用域,作用域链。(代码片段)

...ff1a;在执行过程中,若使用了未声明的变量,那么JavaScript执行会报错。在一个变量定义之前使用它,不会出错,但是该变量的值会为undefined,而不是定义时的值。在一个函数定义之前使用它,不会出错࿰... 查看详情

js重点知识总结(代码片段)

...自执行函数,定义即执行变量提升:Hoisting作用域内提升闭包:closure一个可以访问私有作用域的函数及其所在的运行环境的组合使用闭包定义私有变量:变量私有化模块化:作用域独立化及私有化柯里化:定义多参数函数增加函... 查看详情

立即执行的匿名函数(代码片段)

...nction语句来定义一个函数4.Function对象  Function对象是JavaScript里面的固 查看详情

工作中,如何衡量一个人的javascript编码水平?(代码片段)

1、立即执行函数立即执行函数,即ImmediatelyInvokedFunctionExpression(IIFE),正如它的名字,就是创建函数的同时立即执行。它没有绑定任何事件,也无需等待任何异步操作:(function()//代码)();function()…是一个匿名函数,包围它的一... 查看详情