详谈JavaScript 匿名函数及闭包

合集下载

JavaScript----闭包意义谈

JavaScript----闭包意义谈

JavaScript----闭包意义谈我觉得闭包是⼀种更⾃然的代码形式,可以让你不拘泥于简单的块、函数作⽤域⽽穿透作⽤域。

举2个例⼦,⼀个⽤于隐藏⼀些变量,另⼀个⽤于异步调⽤:1、隐藏变量:Javascript代码1. Function.prototype.bind = function(obj) {2. var _this = this;3. return function() {4. _this.apply(obj,arguments);5. };6. }这个是最原始的Prototype框架⾥bind函数(绑定函数作⽤域)的最简化版本。

在这⾥,我们可以看到调⽤bind后对obj对象的隐藏(这段代码可以理解为⼀种转移作⽤域的代理模式吧)。

2、异步调⽤。

假如我们有⼀段代码Javascript代码1. function test() {2. var a = 1,b=2,c=3;3. alert(a+b+c);4. }需要改成异步延时的,只需要改成Javascript代码1. function test() {2. var a = 1,b=2,c=3;3. setTimeout(function() {4. alert(a+b+c);5. },1000);6. }其实经验上讲,绝⼤多数的同步的地⽅改成异步都都可以⽤上述⽅法,只要将需要异步的部分(通常是从某⼀⾏开始到函数末尾)包含在闭包中,就可以进⾏异步处理了。

其实还有挺多其他应⽤,总之,如果⼼⾥想着“什么是闭包”,“我在⽤闭包”这种事的话,反⽽往往⽤不好闭包。

只要深刻的理解js这种特性,这种作⽤域机制,将闭包使⽤在⽆形之中,才算是真正会使⽤闭包了吧。

9 楼 2011-03-11suiye007 写道谢谢,发现问题所在了,我取的时候也是3,是New⼀个对象,然后,apply的,直接调⽤确实不是,不过,我有点不太明⽩什么时候要⽤闭包,什么时候不要⽤,虽然我的程序中闭包⽤得也⽐较的多,那是不得已的时候才⽤的,能给点经验吗?往⼤⾥说,闭包是⼀种跟⾯向对象技术同样层⾯的“把数据与操作进⾏绑定”的技术。

详解JavaScript匿名函数和闭包

详解JavaScript匿名函数和闭包

详解JavaScript匿名函数和闭包概述在JavaScript前端开发中,函数与对其状态即词法环境(lexical environment)的引⽤共同构成闭包(closure)。

也就是说,闭包可以让你从内部函数访问外部函数作⽤域。

在JavaScript,函数在每次创建时⽣成闭包。

匿名函数和闭包可以放在⼀起学习,可以加深理解。

本⽂主要通过⼀些简单的⼩例⼦,简述匿名函数和闭包的常见⽤法,仅供学习分享使⽤,如有不⾜之处,还请指正。

普通函数普通函数由fucntion关键字,函数名,() 和⼀对{} 组成,如下所⽰:function box(){return 'Hex';}alert(box());匿名函数顾名思义,匿名函数就是没有实际名字的函数。

单独的匿名函数⽆法运⾏,如下所⽰:function (){return 'Hex';}//以上,会报错:缺少标识符如何解决匿名函数不能执⾏的问题呢?有如下⼏种⽅法:1. 把匿名函数赋值给变量,如下所⽰://把匿名函数赋值给变量var box=function(){return 'Hex';}alert(box());2. 通过⾃我执⾏来调⽤函数,格式如下:(匿名函数)()(function(){alert('Hex');})();3. 把匿名函数⾃我执⾏的返回值赋值给变量,如下所⽰:var box=(function(){return 'Hex';})();alert(box);//注意:此处不带括弧4. 或者省去变量,如下所⽰:alert((function() {return 'Hex';})());⾃我执⾏匿名函数如何传递参数呢?如下所⽰:(function(age) {alert('Hex--' + age);})(30);闭包(closure)闭包是由函数以及创建该函数的词法环境组合⽽成。

JavaScript匿名函数(anonymousfunction)与闭包(closure)

JavaScript匿名函数(anonymousfunction)与闭包(closure)

JavaScript匿名函数(anonymousfunction)与闭包(closure)引⼊匿名函数闭包变量作⽤域函数外部访问函数内部的局部变量⽤闭包实现私有成员引⼊闭包是⽤匿名函数来实现。

闭包就是⼀个受到保护的变量空间,由内嵌函数⽣成。

“保护变量”的思想在⼏乎所有的编程语⾔中都能看到。

先看下 JavaScript 作⽤域:JavaScript 具有函数级的作⽤域。

这意味着,不能在函数外部访问定义在函数内部的变量。

JavaScript 的作⽤域⼜是词法性质的(lexically scoped)。

这意味着,函数运⾏在定义它的作⽤域中,⽽不是在调⽤它的作⽤域中。

这是 JavaScript 的⼀⼤特⾊,将在后⾯说明。

把这两个因素结合在⼀起,就能通过把变量包裹在匿名函数中⽽对其加以保护。

你可以这样创建类的私有变量:var baz;(function() {var foo = 10;var bar = 2;baz = function() {return foo * bar;};})();baz();尽管在匿名函数外执⾏,但 baz 仍然可以访问 foo 和 bar。

说明:1,第 1 ⾏,baz 是全局变量;2,第 3 ~第 9 ⾏,定义⼀个匿名函数;3,第 4 和 5 ⾏,foo 和 bar 是匿名函数内的局部变量;第 6 ~ 8 ⾏,在匿名函数内定义⼀个匿名函数,并将其赋值给全局变量 baz;4,第 10 ⾏,调⽤ baz。

若改成 "alert(baz());",将显⽰ 20;5,按理说,在匿名函数外不能访问 foo 和 bar,但是现在可以。

在说明闭包前,先了解⼀下匿名函数。

匿名函数匿名函数是指那些⽆需定义函数名的函数。

匿名函数与 Lambda 表达式(拉姆达表达式)是⼀回事。

唯⼀的不同——语法形式不同。

Lambda 表达式更进⼀步。

本质上,它们的作⽤都是:产⽣⽅法——内联⽅法,也就是说,省去函数定义,直接写函数体。

javascript之闭包理解以及应用场景

javascript之闭包理解以及应用场景

javascript之闭包理解以及应⽤场景半个⽉没写博⽂了,最近⼀直在弄⼩程序,感觉也没啥好写的。

之前读了js权威指南,也写了篇,但是实话实说当初看闭包确实还是⼀头雾⽔。

现在时隔⼀个多⽉(当然这⼀段时间还是⼀直有在看闭包的相关知识)理解就更深⼊了⼀点,下⾯说说我的理解。

1function fn(){2var a = 0;3return function (){4return ++a;5 }6 }如上所⽰,上⾯第⼀个return返回的就是⼀个闭包,那么本质上说闭包就是⼀个函数。

那么返回这个函数有什么⽤呢?那是因为这个函数可以调⽤到它外部的a这个变量。

其实也就是说,return返回的是这个函数 + a这个变量那么,我们现在再来利⽤这个闭包做点事情我们不妨创建⼀个变量var f = fn(); 我们如果 console.log(f) ⼀下就知道,这个f就是return的整个函数体,也就是function () { return ++a;}那么我们执⾏f()就相当于执⾏function函数了,这时,我们多次执⾏f()的话,返回的a数值就会⼀直叠加。

但是如果我们现在再创建⼀个变量var f2 = fn(); 我们运⾏f2()的话,会发现,a的值重置了。

⼜会从0开始了。

这是为什么呢?其实我们可以这样理解,⾸先闭包是⼀个匿名函数,现在我们将它赋予了⼀个变量,那么他就有名字了,那么他每次执⾏完以后就有地⽅存了。

但是每个变量存的地⽅⼜不⼀样,他们相互不关联,所以他们就是独⽴的个体了,所以a得值就不同了。

就当是执⾏了不同的函数,只是恰好函数体是⼀样的罢了。

⾮常感谢提供的思路那么,我们闭包的应⽤场景有什么呢。

本来之前我也⼀直在想,因为我很⽔,所以我写代码⽤到闭包的地⽅并不是很多。

但是今天在看前端的设计模式的时候看到了单例模式,想了下,这不就是闭包的⼀个很好的应⽤场景么?⽐如说我现在的需求是这样的,在⽹页中有时候会需要遮罩层,调⽤的时候我就创建⼀个,但是你不可能每次调⽤创建吧,所以如果存在就⽤以前的,如果不存在就创建新的,但同时有可能我永远都不需要这个遮罩层,所以我也有可能⼀直都不需要创建。

深度剖析JavaScript闭包

深度剖析JavaScript闭包

深度剖析J a v a S c r i p t闭包LELE was finally revised on the morning of December 16, 2020理解 JavaScript 闭包本文结合 ECMA 262 规范详解了闭包的内部工作机制,让 JavaScript 编程人员对闭包的理解从“嵌套的函数”深入到“标识符解析、执行环境和作用域链”等等 JavaScript 对象背后的运行机制当中,真正领会到闭包的实质。

简介Closure所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

闭包是 ECMAScript (JavaScript)最强大的特性之一,但用好闭包的前提是必须理解闭包。

闭包的创建相对容易,人们甚至会在不经意间创建闭包,但这些无意创建的闭包却存在潜在的危害,尤其是在比较常见的浏览器环境下。

如果想要扬长避短地使用闭包这一特性,则必须了解它们的工作机制。

而闭包工作机制的实现很大程度上有赖于标识符(或者说对象属性)解析过程中作用域的角色。

关于闭包,最简单的描述就是 ECMAScript 允许使用内部函数--即函数定义和函数表达式位于另一个函数的函数体内。

而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。

当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

也就是说,内部函数会在外部函数返回后被执行。

而当这个内部函数执行时,它仍然必需访问其外部函数的局部变量、参数以及其他内部函数。

这些局部变量、参数和函数声明(最初时)的值是外部函数返回时的值,但也会受到内部函数的影响。

遗憾的是,要适当地理解闭包就必须理解闭包背后运行的机制,以及许多相关的技术细节。

虽然本文的前半部分并没有涉及 ECMA 262 规范指定的某些算法,但仍然有许多无法回避或简化的内容。

JavaScript闭包详解

JavaScript闭包详解

JavaScript闭包详解JavaScript内部原理系列-闭包(Closures)概要本⽂将介绍⼀个在JavaScript经常会拿来讨论的话题 —— 闭包(closure)。

闭包其实已经是个⽼⽣常谈的话题了;有⼤量⽂章都介绍过闭包的内容,尽管如此,这⾥还是要试着从理论⾓度来讨论下闭包,看看ECMAScript中的闭包内部究竟是如何⼯作的。

概论在讨论ECMAScript闭包之前,先来介绍下函数式编程(与ECMA-262-3 标准⽆关)中⼀些基本定义。

然⽽,为了更好的解释这些定义,这⾥还是拿ECMAScript来举例。

众所周知,在函数式语⾔中(ECMAScript也⽀持这种风格),函数即是数据。

就⽐⽅说,函数可以保存在变量中,可以当参数传递给其他函数,还可以当返回值返回等等。

这类函数有特殊的名字和结构。

定义函数式参数(“Funarg”) —— 是指值为函数的参数。

如下例⼦:function exampleFunc(funArg) {funArg();}exampleFunc(function () {alert('funArg');});上述例⼦中funArg的实参是⼀个传递给exampleFunc的匿名函数。

反过来,接受函数式参数的函数称为⾼阶函数(high-order function 简称:HOF)。

还可以称作:函数式函数或者偏数理的叫法:操作符函数。

上述例⼦中,exampleFunc 就是这样的函数。

此前提到的,函数不仅可以作为参数,还可以作为返回值。

这类以函数为返回值的函数称为 _带函数值的函数(functions with functional value or function valued functions)。

(function functionValued() {return function () {alert('returned function is called');};})()();//这种()直接执⾏的⽅式要熟悉。

Javascript基础知识——匿名函数和闭包(1)

Javascript基础知识——匿名函数和闭包(1)

Javascript基础知识——匿名函数和闭包(1)利用晚上的一点时间来总结一下匿名函数和闭包的问题!首先要搞清楚什么事匿名函数——很简单没有名字的函数!什么是闭包?可以访问一个函数作用域里面变量的函数!function(){alert("tmh");}这个就是匿名函数。

但是,如果这么执行的话是错误的!(function(){alert("tmh");})();匿名函数必须让他执行起来!我们平时最常用的匿名函数,是将一个匿名函数赋值给一个变量!var box=function(){alert("tmh");}下面来一个比较特殊的函数——函数里面的函数!很特殊,估计只有javascript 这个奇葩的语言里才有的东西!function box(){return function(){return "tang!";}}很有性格的一种函数。

反正我以前学的语言里没有这么写法的!javascript是唯一这么写的!执行这个函数后,返回一个函数!我们该如何调用呢?box()();为什么要这么写,这么写有什么好处?我不知道,也许后面的项目里有用吧!接下来就是闭包了,这个东西估计花头就透了!!刚才说了,闭包就是访问函数作用域里面变量的函数!好,马上走起!function box(){var user="tang";return function(){return user;}}这段代码就不一样了!函数里面的user是个局部变量,我们在外面是访问不到的!只有里面的匿名函数可以访问!我们box()一下后,返回了一个匿名函数,这个函数可以返回变量user的值!从这里,我们可以看出,匿名函数有驻留变量在内存中的作用!我们来看一个累加函数!var count=0;function box(){count+=1;}这个函数可以达到累加的作用,但是这里我们用了全局变量,全局变量容易被污染。

js 面试题 闭包

js 面试题 闭包

js 面试题闭包JavaScript面试题:闭包JavaScript中的闭包是一个常见的面试题,它涉及到JavaScript中的作用域和变量访问的问题。

本文将通过介绍闭包的概念、使用场景和常见面试题来详细讨论闭包以及相关内容。

一、闭包的概念闭包是指函数和其相关的引用环境组合而成的实体。

简而言之,闭包是函数以及它能够访问的外部变量的合集。

具体来说,一个闭包可以访问在其定义时可访问的所有变量,即使在函数执行结束后,这些变量仍然可以被访问。

二、闭包的使用场景闭包在JavaScript中有广泛的应用场景,下面介绍了一些常见的使用情况:1. 封装私有变量闭包可以用于创建模块化的代码结构,封装私有变量和方法。

通过使用闭包,我们可以创建一个具有私有变量和公共方法的对象。

示例代码:```javascriptfunction createCounter() {let count = 0;return {increment() {count++;},decrement() {count--;},getCount() {return count;}};}const counter = createCounter(); counter.increment();counter.increment();console.log(counter.getCount()); // 输出: 2 ```2. 延迟执行闭包可以用于创建延迟执行的函数,即将函数和其相关的数据封装在闭包中。

示例代码:```javascriptfunction delayExecution(message, delay) {setTimeout(function() {console.log(message);}, delay);}delayExecution('Hello', 2000); // 2秒后输出: Hello```3. 保存函数状态闭包可以用于保存函数的状态,以供后续调用时使用。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

详谈JavaScript 匿名函数及闭包1、匿名函数函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途。

匿名函数:就是没有函数名的函数。

1.1 函数的定义,首先简单介绍一下函数的定义,大致可分为三种方式第一种:这也是最常规的一种代码如下:function double(x){return 2 * x;}第二种:这种方法使用了Function构造函数,把参数列表和函数体都作为字符串,很不方便,不建议使用。

代码如下:var double = new Function('x', 'return 2 * x;');第三种:var double = function(x) { return 2* x; }注意“=”右边的函数就是一个匿名函数,创造完毕函数后,又将该函数赋给了变量square。

1.2 匿名函数的创建第一种方式:就是上面所讲的定义square函数,这也是最常用的方式之一。

第二种方式:代码如下:(function(x, y){alert(x + y);})(2, 3);这里创建了一个匿名函数(在第一个括号内),第二个括号用于调用该匿名函数,并传入参数。

2、闭包闭包的英文单词是closure,这是JavaScript中非常重要的一部分知识,因为使用闭包可以大大减少我们的代码量,使我们的代码看上去更加清晰等等,总之功能十分强大。

闭包的含义:闭包说白了就是函数的嵌套,内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕(这点涉及JavaScript作用域链)。

示例一代码如下:function checkClosure(){var str = 'rain-man';setTimeout(function(){ alert(str); } //这是一个匿名函数, 2000);}checkClosure();这个例子看上去十分的简单,仔细分析下它的执行过程还是有许多知识点的:checkClosure 函数的执行是瞬间的(也许用时只是0.00001毫秒),在checkClosure的函数体内创建了一个变量str,在checkClosure执行完毕之后str并没有被释放,这是因为setTimeout内的匿名函数存在这对str的引用。

待到2秒后函数体内的匿名函数被执行完毕,str才被释放。

示例二,优化代码代码如下:function forTimeout(x, y){alert(x + y);}function delay(x , y , time){setTimeout('forTimeout(' + x + ',' + y + ')' , time);}/*** 上面的delay函数十分难以阅读,也不容易编写,但如果使用闭包就可以让代码更加清晰* function delay(x , y , time){* setTimeout(* function(){* forTimeout(x , y)* }* , time);* }3、举例匿名函数最大的用途是创建闭包(这是JavaScript语言的特性之一),并且还可以构建命名空间,以减少全局变量的使用。

示例三:代码如下:var oEvent = {};(function(){var addEvent = function(){ /*代码的实现省略了*/ };function removeEvent(){}oEvent.addEvent = addEvent;oEvent.removeEvent = removeEvent;})();在这段代码中函数addEvent和removeEvent都是局部变量,但我们可以通过全局变量oEvent 使用它,这就大大减少了全局变量的使用,增强了网页的安全性。

我们要想使用此段代码:oEvent.addEvent(document.getElementById('box') , 'click' , function(){});示例四:代码如下:var rainman = (function(x , y){return x + y;})(2 , 3);/*** 也可以写成下面的形式,因为第一个括号只是帮助我们阅读,但是不推荐使用下面这种书写格式。

* var rainman = function(x , y){* return x + y;* }(2 , 3);*/在这里我们创建了一个变量rainman,并通过直接调用匿名函数初始化为5,这种小技巧有时十分实用。

示例五:代码如下:var outer = null;(function(){var one = 1;function inner (){one += 1;alert(one);}outer = inner;})();outer(); //2outer(); //3outer(); //4这段代码中的变量one是一个局部变量(因为它被定义在一个函数之内),因此外部是不可以访问的。

但是这里我们创建了inner函数,inner函数是可以访问变量one的;又将全局变量outer引用了inner,所以三次调用outer会弹出递增的结果。

4、注意4.1 闭包允许内层函数引用父函数中的变量,但是该变量是最终值示例六:代码如下:/*** <body>* <ul>* <li>one</li>* <li>two</li>* <li>three</li>* <li>one</li>* </ul>*/var lists = document.getElementsByTagName('li');for(var i = 0 , len = lists.length ; i < len ; i++){lists[ i ].onmouseover = function(){alert(i);};}你会发现当鼠标移过每一个<li&rt;元素时,总是弹出4,而不是我们期待的元素下标。

这是为什么呢?注意事项里已经讲了(最终值)。

显然这种解释过于简单,当mouseover事件调用监听函数时,首先在匿名函数(function(){ alert(i); })内部查找是否定义了i,结果是没有定义;因此它会向上查找,查找结果是已经定义了,并且i的值是4(循环后的i值);所以,最终每次弹出的都是4。

解决方法一:代码如下:var lists = document.getElementsByTagName('li');for(var i = 0 , len = lists.length ; i < len ; i++){(function(index){lists[ index ].onmouseover = function(){alert(index);};})(i);}解决方法二:代码如下:var lists = document.getElementsByTagName('li');for(var i = 0, len = lists.length; i < len; i++){lists[ i ].$$index = i; //通过在Dom元素上绑定$$index属性记录下标lists[ i ].onmouseover = function(){alert(this.$$index);};}解决方法三:代码如下:function eventListener(list, index){list.onmouseover = function(){alert(index);};}var lists = document.getElementsByTagName('li');for(var i = 0 , len = lists.length ; i < len ; i++){eventListener(lists[ i ] , i);}4.2 内存泄露使用闭包十分容易造成浏览器的内存泄露,严重情况下会是浏览器挂死。

可以参考下面内容预防:JavaScript垃圾回收机制JavaScript不需要手动地释放内存,它使用一种自动垃圾回收机制(garbage collection)。

当一个对象无用的时候,即程序中无变量引用这个对象时,就会从内存中释放掉这个变量。

复制代码代码如下:var s = [ 1, 2 ,3];var s = null;//这样原始的数组[1 ,2 ,3]就会被释放掉了。

3、循环引用三个对象A 、B 、CAàBàC :A的某一属性引用着B,同样C也被B的属性引用着。

如果将A清除,那么B、C也被释放。

AàBàCàB :这里增加了C的某一属性引用B对象,如果这是清除A,那么B、C不会被释放,因为B和C之间产生了循环引用。

复制代码代码如下:var a = {};a.pro = { a:100 };a.pro.pro = { b:100 };a = null ;//这种情况下,{a:100}和{b:100}就同时也被释放了。

var obj = {};obj.pro = { a : 100 };obj.pro.pro = { b : 200 };var two = obj.pro.pro;obj = null;//这种情况下{b:200}不会被释放掉,而{a:100}被释放了。

4、循环引用和闭包复制代码代码如下:function outer(){var obj = {};function inner(){//这里引用了obj对象}obj.inner = inner;}这是一种及其隐蔽的循环引用,。

当调用一次outer时,就会在其内部创建obj和inner两个对象,obj的inner属性引用了inner;同样inner也引用了obj,这是因为obj仍然在inn erFun的封闭环境中,准确的讲这是由于JavaScript特有的“作用域链”。

因此,闭包非常容易创建循环引用,幸运的是JavaScript能够很好的处理这种循环引用。

5、IE中的内存泄漏IE中的内存泄漏有好几种,这里有详细的解释(/en-us/libra ry/bb250448.aspx)。

这里只讨论其中一种,即循环引用所造成的内存泄漏,因为,这是一种最普遍的情况。

当在DOM元素或一个ActiveX对象与普通JavaScript对象之间存在循环引用时,IE在释放这类变量时存在特殊的困难,最好手动切断循环引用,这个bug在IE 7中已经被修复了(/blog/archives/2006/04/ie_7_and_javasc.html)。

相关文档
最新文档