详谈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. 保存函数状态闭包可以用于保存函数的状态,以供后续调用时使用。

匿名函数和闭包

匿名函数和闭包

匿名函数和闭包匿名函数就是没有名字的函数,闭包是可访问⼀个函数作⽤域⾥变量的函数。

声明:本节内容需要有⾯向对象和少量设计模式基础,否则⽆法听懂。

// //普通函数// function box(){// return 'lee';// };// //匿名函数// function(){ //执⾏的时候会显⽰错误// return 'lee';// };//把匿名函数⾃我执⾏的返回值赋值给变量var b=function(){ //单独的匿名函数,是⽆法执⾏的就算执⾏也⽆法调⽤return 'lee';};alert(b); //这样会打印出匿名函数的结构alert(b()); //这样会打印出匿名函数的返回值// 匿名函数⾃我执⾏(function (){ //(匿名函数)(); 第⼀圆括号放匿名函数,第⼆个圆括号执⾏return 'lee'; //()表⽰执⾏})();alert((function (){return 'lee';})());//⾃我执⾏匿名函数的传参alert((function(age,name){return age+name;})(100,200));//函数⾥的匿名函数function box(){return function(){ //闭包return 'lee';}};alert(box()()); //box() 返回是匿名函数的结构 box()()返回函数中匿名函数的返回值闭包: 闭包是指有权访问另⼀个函数作⽤域中的变量的函数,创建闭包的常见的⽅式,就是在⼀个函数内部创建另⼀个函数,通过另⼀个函数访问这个函数的局部变量。

//通过闭包可以返回局部变量function box(){return function(){ //通过匿名函数返回box()局部变量return 'Lee';};};alert(box()()); //通过box()()来直接调⽤匿名函数返回值var b=box();alert(b()); //另⼀种调⽤匿名函数返回值使⽤闭包有⼀个优点,也是他的缺点;就是可以把局部变量留在内存中,可以避免使⽤全局变量。

js中的匿名函数

js中的匿名函数

js中的匿名函数匿名函数顾名思义指的是没有名字的函数,在实际开发中使⽤的频率⾮常⾼!也是学好JS的重点。

匿名函数:没有实际名字的函数。

⾸先我们声明⼀个普通函数://声明⼀个普通函数,函数的名字叫fnfunction fn(){console.log("张培跃");}然后将函数的名字去掉即是匿名函数://匿名函数,咦,运⾏时,你会发现报错啦!function (){console.log("张培跃");}到此,你会发现单独运⾏⼀个匿名函数,由于不符合语法要求,报错啦!解决⽅法只需要给匿名函数包裹⼀个括号即可://匿名函数在其它应⽤场景括号可以省略(function (){//由于没有执⾏该匿名函数,所以不会执⾏匿名函数体内的语句。

console.log("张培跃");})如果需要执⾏匿名函数,在匿名函数后⾯加上⼀个括号即可⽴即执⾏!(function (){//此时会输出张培跃console.log("张培跃");})()倘若需要传值,直接将参数写到括号内即可:(function (str){//此时会输出张培跃好帅!console.log("张培跃"+str);})("好帅!")匿名函数的应⽤场景1、事件<input type="button" value="点我啊!" id="sub"><script>//获得按钮元素var sub=document.querySelector("#sub");//给按钮增加点击事件。

sub.onclick=function(){alert("当点击按钮时会执⾏到我哦!");}</script>2、对象var obj={name:"张培跃",age:18,fn:function(){return "我叫"++"今年"+this.age+"岁了!";}};console.log(obj.fn());//我叫张培跃今年18岁了!3、函数表达式//将匿名函数赋值给变量fn。

js闭包函数

js闭包函数

js闭包函数⼀. 匿名函数javascript中: (function(){})()是,主要利⽤函数内的变量作⽤域百,避免产⽣全局变量,影响整体页⾯环境,增加代码的兼容性。

(function(){})是⼀个标准的函数定义,但是没有复制给任何变量。

所以是没有名字的函数,叫。

没有名字就度⽆法像普通函数那样调⽤了,所以在他定义完知成后就马上调⽤他,后⾯的括号()是运⾏这个函数的意思⼆. 闭包⽰例1. ⾸先⽴即执⾏匿名函数获得闭包函数,此时闭包函数可以拿到上⼀层函数的变量保证不被销毁2. 此时counter就类似私有变量,只能通过闭包函数进⾏修改3. 缺点⼤量内存占⽤,导致局部变量不会被垃圾回收,严重会导致内存泄漏(内存泄漏是指程序中⼰动态分配的堆内存由于某种原因程序未释放或⽆法释放,造成系统内存的浪费,导致程序运⾏速度减慢甚⾄系统崩溃等严重后果)var add = (function () {var counter = 0;return function () {return counter += 1;}})();add();add();add();// 计数器为 34. 经典⾯试题,循环中使⽤闭包解决var定义函数的问题⾸先因为setTimeout是个异步函数,所有会先把循环全部执⾏完毕,这时候i就是 6 了,所以会输出⼀堆 6。

for ( var i=1; i<=5; i++) {setTimeout( function timer() {console.log( i );}, i*1000 );}5. 还可以使⽤let定义i解决此问题,因为对于let来说,他会创建⼀个块级作⽤域for ( let i=1; i<=5; i++) {setTimeout( function timer() {console.log( i );}, i*1000 );}。

javaScriptFunction(函数)闭包匿名函数this对象

javaScriptFunction(函数)闭包匿名函数this对象

javaScriptFunction(函数)闭包匿名函数this对象1. Function函数接受的参数类型、个数没有限定。

参数在内部是⽤数组arguments来存储的。

因此函数没有重载。

可以提供arguments【i】来表⽰传⼊的参数4.1创建使⽤函数声明和函数表达式创建,也可以使⽤Function()构造函数Function sum(num1,num2){函数声明}Var sum = function(num1,num2){函数表达式}解析器会率先读取函数声明,并使其在执⾏任何代码之前可⽤;因为在代码执⾏之前,解析器就已经通过⼀个名为函数声明提升的过程,读取并将函数声明添加到执⾏环境,js引擎在第⼀遍会声明函数并将它们放到源代码树的顶部。

函数表达式须等到解析器执⾏到它所在代码⾏,才会真正被解析。

4.2函数内部属性Arguments指代参数Callee:arguments.callee指代拥有这个arguments对象的函数。

在递归调⽤时,⾮常有⽤。

Caller:保存着调⽤当前函数的函数的引⽤Function outer(){Inner();}Function inner(){Alert(inner.caller);//警告框中显⽰outer()函数的源代码,等价于arguments.callee.caller}This:this引⽤的是函数据以执⾏的环境对象。

4.3 call()和apply()扩⼤函数赖以运⾏的作⽤域每个函数都包含这两个⾮继承⽽来的⽅法。

这两个⽅法⽤途都是在特定的作⽤域⾥调⽤函数,实际上是设置函数体内的this值。

Apply()接受2个参数,⼀个是其中函数运⾏的作⽤域,另⼀个是参数数组Call()接受多个参数,⼀个是其中函数运⾏的作⽤域,其他是传递给函数的参数必须逐个列举出来Window.color = “red”;Var o = {Color:”blue”};Function sayColor(){Alert(this.color);}sayColor(); //redsayColor.call(window); //redsayColor.call(this); //redsayColor(o); //blue4.4java与js创建函数Java是:修饰符返回类型函数名(参数类型参数名){函数体}Js是:函数声明和函数表达式函数声明:function 函数名(参数名){函数体}函数表达式:var 函数名 = function(参数名){函数体}4.5匿名函数在function后⾯没有跟函数名的函数称为匿名函数。

Javascript匿名函数与闭包(转)

Javascript匿名函数与闭包(转)

Javascript匿名函数与闭包(转)请见如下⼀个闭包⽰例:color = "red";var obj = {color: "blue",getColor: function () {function displayColor() {return this.color;}return displayColor();}}console.log(obj.getColor());在getColor函数内部再定义了⼀个displayColor,再⼜定义了⼀个displayColor函数,从⽽形成闭包,最后将地上displayColor函数返回,这⾥发现这样定义其实作⽤不⼤,可以使⽤匿名函数替代直接返回:color = "red";var obj = {color:"blue",getColor: function () {return function() {return this.color;}}}console.log(obj.getColor()()); //输出 red闭包中匿名函数和this对象在javascript 中this 对象是基于函数的执⾏环境绑定的:在全局函数中, this等于全局环境即 window (浏览器环境)或者globle(node 中),⽽当函数作为某个对象的⽅法调⽤时this等于该对象。

不过匿名函数的执⾏环境具有全局性,其this 通常指向window(浏览器)或者globle(node环境),因此上⾯例⼦中,输出的是全局对象的 color定义。

为什么没有获得闭包外⾯定义的blue呢?如前⽂所述,函数被调⽤时,其活动对象会取得两个特殊的变量,arguments和this,因此在搜索的时候在作⽤域链的最前端即当前活动对象中就查找到了,不会进⼀步向上层查找。

不过我们可以把外部作⽤域的this对象保存在⼀个闭包能够访问到的变量⾥,这样就能够访问外层对象了:color = "red";var obj = {color:"blue",getColor: function () {var self=this;return function() {return self.color;}}}console.log(obj.getColor()()); //输出 blue最后,看⼀道百度2015年前端开发南京站笔试题:var myObject = {foo: "bar",func: function() {var self = this;console.log("outer func: this.foo = " + this.foo); //输出 barconsole.log("outer func: self.foo = " + self.foo); //输出 bar(function() {console.log("inner func: this.foo = " + this.foo); //输出 undefinedconsole.log("inner func: self.foo = " + self.foo); //输出 bar}());}};myObject.func();问,输出结果是什么?相信现在应该⽐较好理解了。

深入理解javascript函数参数与闭包

深入理解javascript函数参数与闭包

深⼊理解javascript函数参数与闭包最近在学习javascript的函数,函数是javascript的⼀等对象,想要学好javascript,就必须深刻理解函数。

本⼈把学习的过程整理成⽂章,⼀是为了加深⾃⼰函数的理解,⼆是给读者提供学习的途径,避免⾛弯路。

内容有些多,但都是笔者对于函数的总结。

1.函数参数 1.1:参数是什么 1.2:参数的省略 1.3:参数默认值 1.4:参数传递⽅式 1.5:同名参数 1.6:arguments对象2.闭包 2.1:闭包定义 2.2:⽴即调⽤的函数表达式(IIFE, Immediately invoked function expression)1.函数参数 1.1:参数是什么 在定义⼀个函数时,有时候需要为函数传递额外的数据,不同的外部数据会得到不同的结果,这种外部数据就叫做参数。

function keith(a){return a+a;}console.log(keith(3)); //6上⾯代码中,给keith函数传递了参数a,并且返回了a+a表达式。

1.2:参数的省略函数参数不是必须的,javascript规范允许省略调⽤时传递的实际参数。

function keith(a, b, c) {return a;}console.log(keith(1, 2, 3)); //1console.log(keith(1)); //1console.log(keith()); // 'undefined'上⾯代码中,keith函数定义了三个参数,但是在调⽤时⽆论传递了多少个参数,javascript都不会报错。

被省略的参数的默认值就变为undefined。

了解函数定义与函数作⽤域的都知道,函数的length属性会返回参数个数。

需要注意的是,length属性与实际参数的个数⽆关,只是返回形式参数的个数。

(实际参数:调⽤时传递的参数。

形式参数:定义时传递的参数。

浅谈JavaScript的闭包函数

浅谈JavaScript的闭包函数

浅谈JavaScript的闭包函数 在JavaScript中,闭包恐怕是很多⼈不能理解的⼀个概念了,甚⾄很多⼈也会把闭包和匿名函数混淆。

 闭包是有权访问另⼀个函数作⽤域中的变量的函数。

⾸先要明⽩的就是,闭包是函数。

由于要求它可以访问另⼀个函数的作⽤于中的变量,所以我们往往是在⼀个函数的内部创建另⼀个函数,⽽“另⼀个函数”就是闭包。

 ⽐如之前提到过的作为⽐较函数:function createComparisonFunction(propertyName){return function(object1,object2){var value1=object1[propertyName];var value2=object2[propertyName];if(value1<value2){ return="" -1;="" }else="" if(value1="">value2){return 1;}else{return 0;}};}</value2){> 在这个函数中,由于return的函数它访问了包含函数(外部函数)的变量propertyName,所以我们认为这个函数即为闭包。

即使这个闭包被返回了,⽽且是在其他地⽅调⽤了,但是它仍然可以访问propertyName,之所以还能够访问到propertyName这个变量,是因为内部函数(闭包)的作⽤域链中包含着createComparisonFunction函数的作⽤域。

因此,要彻底搞清楚闭包,就需要彻底搞清楚函数被调⽤时发⽣了什么以及作⽤域链的有关知识。

 当某个函数被调⽤时,会创建⼀个执⾏环境(函数⼀旦被调⽤,则进⼊函数执⾏环境)和相应的作⽤域链(作⽤域链是随着执⾏环境的不同⽽动态变化的)。

(对于函数⽽⾔)之后使⽤arguments和其他命名参数的值来初始化函数的活动对象(每个执⾏环境都有⼀个变量对象,对于函数成为活动对象)。

【深入】深入研究JavaScript的匿名函数

【深入】深入研究JavaScript的匿名函数

【关键字】深入jQuery片段:(function(){//这里忽略jQuery所有实现})();(function(){ //这里忽略jQuery所有实现})();半年前初次接触jQuery的时候,我也像其他人一样很兴奋地想看看源码是什么样的。

然而,在看到源码的第一眼,我就迷糊了。

为什么只有一个匿名函数又没看到运行(当然是运行了……),就能有jQuery这么个函数库了?于是,我抱着疑问来到CSDN。

结果相信现在很多人都很清楚了(因为在我之后也不乏来者,呵呵~)。

当一个匿名函数被括起来,然后再在后面加一个括号,这个匿名函数就能立即运行起来!真神奇哦!嘿嘿!胡闹到此为止。

在这一节,我们碰到的jQuery片段是一组立即运行的匿名函数。

而这种用法在论坛上也曾引起过激辩——这段代码究竟属不属于闭包呢?带着这个疑问,我们从基础开始,分析每个关键要素,寻找属于自己的答案。

(没错,自己的答案!在我看来,所有理论只是形式,只要它有利于我们的应用实现,就是可取的——黑猫白猫,抓到老鼠的就是好猫!)要说匿名函数,我们首先要由函数本身说起。

函数的定义如下:函数是将唯一的输出值赋予给每一输入的“法则”。

当然,这只是数学上的定义。

但是,在计算机编程语言中,函数的定义也八九不离十。

因为,我们都知道,计算机中的函数,也类似数学定义中的描述,它是将输入的若干数据,经过代码设定的逻辑操作处理后,返回唯一的输出的一组代码组合块。

——当然,特例是,输入的数据为空或输出的数据为空,或者两者都为空。

下面,我们先初步了解一下和匿名函数相关的概念。

函数声明(function 语句)要使用一个函数,我们就得首先声明它的存在。

而我们最常用的方式就是使用function 语句来定义一个函数,如:function abc(){// code to process}function abc(){ // code to process }当然,你的函数也可以是带参数的,甚至是带返回值的。

深入理解Javascript闭包(closure)

深入理解Javascript闭包(closure)

最近在网上查阅了不少javascript闭包(closure)相关的资料,写的大多是非常的学术和专业。

对于初学者来说别说理解闭包了,就连文字叙述都很难看懂。

撰写此文的目的就是用最通俗的文字揭开Javascript闭包的真实面目。

一、什么是闭包?官方的解释是:所谓闭包,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

相信很少有人能直接看懂这句话,因为他描述的太学术。

我想用如何在Javascript中创建一个闭包来告诉你什么是闭包,因为跳过闭包的创建过程直接理解闭包的定义是非常困难的。

看下面这段代码:function a(){var i=0;function b(){alert(++i);}return b;}var c = a();c();这段代码有两个特点:1、函数b嵌套在函数a内部;2、函数a返回函数b。

这样在执行完var c=a()后,变量c实际上是指向了函数b,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。

这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说:当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。

我猜想你一定还是不理解闭包,因为你不知道闭包有什么作用,下面让我们继续探索。

二、闭包有什么作用?简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。

这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。

在上面的例子中,由于闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c(),i都是自加1后alert出i的值。

那么我们来想象另一种情况,如果a返回的不是函数b,情况就完全不同了。

因为a 执行完后,b没有被返回给a的外界,只是被a所引用,而此时a也只会被b引用,因此函数a和b互相引用但又不被外界打扰(被外界引用),函数a和b就会被GC回收。

个人对js闭包的理解

个人对js闭包的理解

个⼈对js闭包的理解闭包算是前端⾯试的基础题,但我看了很多关于闭包的⽂章博客,但感觉很多对于闭包的理想还是有分歧的,现在⽹上对闭包的理解⼀般是两种:1. 有些⽂章认为闭包必须要返回嵌套函数中⾥⾯⽤到外⾯函数局部变量的⽅法才叫闭包,有两个条件:1)、函数嵌套,内部函数要⽤到外部函数的局部变量 2)、内部函数必须返回2. 有些⽂章认为只要函数嵌套内部函数⽤到了外部局部变量就是闭包,不要返回内部函数我们先看看闭包的定义到底是什么,然后在来分析我在学习js的时候不同阶段对闭包的误解。

在《javascript⾼级程序设计中》对闭包定义是这样的:“闭包是指有权限访问另⼀个函数作⽤域中的变量的函数。

“这⾥没有提到这个函数必须要return出来,我们在看看《javascript语⾔精粹》中对闭包的定义是⽤⼀段很误导⼈的代码例⼦来解释闭包:var quo=function(status){return{get_status:function(){return status;}}}var myQuo=quo("amazed");document.writeln(myQuo.get_status());"即使quo返回了,但get_status⽅法仍然享有访问quo对象的status属性的特权,get_status⽅法并不是访问该参数的⼀个副本,它访问的是该参数本⾝,只是可能的,因为该函数可以访问它被创建时所处的上下⽂环境,这被称为闭包. "这是很多解释闭包的⽂章最常⽤的解释案例,所以导致新⼿第⼀次看这种解释产⽣⼀个误导,说必须要return这个函数,但我们看看《javascript语⾔精粹》这段解释中最后强调的是该函数可以访问被创建时所处的上下⽂环境,强调的是访问外部函数的局部变量,⽽⽤这个例⼦是因为这个例⼦是闭包的更为复杂的应⽤,因为你在函数嵌套中,内部函数的运⾏只能在外部函数中执⾏,要在全局变量中运⾏不了,如果我们要在全局运⾏⼀个⽐较容易理解的⽅法是:var get_status;var quo=function(status){get_status=function(){return status;}}quo("amazed");document.writeln( get_status());那这种是不是闭包呢?对上⾯代码进⾏优化利⽤js 可以return函数代码简化了很多。

  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)。

相关文档
最新文档