js匿名函数和闭包总结
js匿名函数和闭包总结
一、总结
一句话总结:匿名函数的最主要作用是创建闭包,闭包就是将函数内部和函数外部连接起来的一座桥梁。内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕。闭包可以用来模仿块级作用域等等。
匿名函数 闭包:匿名函数的最主要作用是创建闭包,闭包就是将函数内部和函数外部连接起来的一座桥梁。内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕。闭包可以用来模仿块级作用域等等
1、js匿名函数基本格式?
匿名函数 赋值 变量
立即执行 匿名函数 ()()
return 匿名函数
没有名字 可以赋值
//情况1.把匿名函数赋值给变量
var fn=function (){
alert('我是匿名函数')
}
alert(fn) //会将函数表达式输出
fn() //情况2.匿名函数通过表达式自我执行
(function (){
alert('我是匿名函数')
}
)()
var name='The Window';
var obj={
name:'my obj',
get:function(){
return function(){
return this.name;
}
}
} alert(obj.get()()) //这次返回的是全局变量 'The Window'
alert(obj.get().call(obj))//这次又返回的是'my obj',因为call()强制改变了this的指向
2、js 中的匿名函数如何自己运行?
(匿名函数)()
因为js中的()可以将函数代码段运行,也可以将变量转化为函数
(function(m,n){
alert(m+n)
})(1000,1000)
匿名函数
没有函数名字的函数
- 单独的匿名函数是无法运行和调用的
- 可以把匿名函数赋值给变量
- 通过表达式自我执行,语法:(匿名函数)()
- 匿名函数传递参数,语法:(匿名函数)(参数)
3、js中的匿名函数如何传递参数?
()() 括号 传参
匿名就是()()的格式
//匿名函数传递参数
function myfn(m,n){
alert(m+n)
}
myfn(100,100); (function(m,n){
alert(m+n)
})(1000,1000)
4、js变量后的()可以表示哪些意思?
变量 变成 方法
执行 匿名函数
a、将变量变成方法
b、放在匿名函数后面,用来执行匿名函数,这样做的话匿名函数本身也要用括号扩起来,
5、js中的闭包是什么?
函数 嵌套 匿名函数
在一个函数中嵌套了一个匿名函数,匿名函数可以访问这个函数里面的变量
闭包的相关概念
- 闭包的英文单词是closure,是指有权访问另一个函数作用域中变量的函数。
- 在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕。
- 这是JavaScript中非常重要的一部分知识,因为使用闭包可以大大减少我们的代码量,使我们的代码看上去更加清晰等等,总之功能十分强大。
注:这些概念了解即可,接下来我们将通过实例来进行了解。
6、匿名函数最大的作用是什么?
创建闭包
闭包的相关概念
- 闭包的英文单词是closure,是指有权访问另一个函数作用域中变量的函数。
- 在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕。
- 这是JavaScript中非常重要的一部分知识,因为使用闭包可以大大减少我们的代码量,使我们的代码看上去更加清晰等等,总之功能十分强大。
注:这些概念了解即可,接下来我们将通过实例来进行了解。
7、alert(myfn);alert(myfn());alert(myfn()())得到的结果分别是什么?
整个函数表达式 匿名函数表达式 执行结果
function myfn(){ return function (){ return('**********') }
} //alert(myfn) //输出整个函数表达式
//alert(myfn()) //输出匿名函数表达式 //调用方式1
alert(myfn()())
8、闭包的用途是什么?
局部变量 常驻内存
闭包的相关知识点
- 常见的方式是在函数内部创建另一个函数
- 闭包的第一个用途:通过闭包可以访问局部变量
- 闭包的第二个用途:可以让局部变量的值始终保持在内存中
- 优点:可以把局部变量驻留在内存中,可以避免使用全局变量;
全局变量在复杂程序中会造成许多麻烦(比如命名冲突,垃圾回收等),所以推荐使用私有的,封装的局部变量。而闭包可以实现这一点。
- 缺点:由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存;所以过度使用闭包会导致性能下降;
- 优点:可以把局部变量驻留在内存中,可以避免使用全局变量;
- 循环函数中的匿名函数和闭包问题
9、add()()的方式为何无法让闭包实现函数局部变量的累加?
初始化
// add()();add()();add()();//这种调用方式会出错,因为每次调用 num都会初始化一次;
var fn=add() ;fn();fn();fn();//只在这里初始化一次,后边调用的时候执行的是里边的匿名函数
function add(){ var num= 100; // 这里改为局部变量; return function(){
num++;
alert(num);
} }; // add()();add()();add()();//这种调用方式会出错,因为每次调用 num都会初始化一次; var fn=add()//只在这里初始化一次,后边调用的时候执行的是里边的匿名函数 fn();fn();fn(); fn=null //应及时解除引用,否则会占用更多存
10、如何解决闭包将局部变量注入内存的缺点?
赋值 null
fn=null //应及时解除引用,否则会占用更多存
闭包的相关知识点
- 常见的方式是在函数内部创建另一个函数
- 闭包的第一个用途:通过闭包可以访问局部变量
- 闭包的第二个用途:可以让局部变量的值始终保持在内存中
- 优点:可以把局部变量驻留在内存中,可以避免使用全局变量;
全局变量在复杂程序中会造成许多麻烦(比如命名冲突,垃圾回收等),所以推荐使用私有的,封装的局部变量。而闭包可以实现这一点。
- 缺点:由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存;所以过度使用闭包会导致性能下降;
- 优点:可以把局部变量驻留在内存中,可以避免使用全局变量;
- 循环函数中的匿名函数和闭包问题
function add(){ var num= 100; // 这里改为局部变量; return function(){
num++;
alert(num);
} }; // add()();add()();add()();//这种调用方式会出错,因为每次调用 num都会初始化一次; var fn=add()//只在这里初始化一次,后边调用的时候执行的是里边的匿名函数 fn();fn();fn(); fn=null //应及时解除引用,否则会占用更多存
11、js如何让循环中的匿名函数和闭包接收到的i正确?
匿名函数 立即执行
匿名函数 内 匿名函数 传参数
函数内部的匿名函数立即执行
//让匿名函数立即执行来赋值
function fun(){
var arr=[];
for(var i=0; i<5; i++){
arr[i]=(function(){
return '元素'+i;
})()
}
return arr
}
var Bb=fun()
alert(Bb.length)
alert(Bb)
// for(var i=0; i<5; i++){ // alert(Bb[i])
// }
匿名函数内部加一层匿名函数(加传参):常见结构
//通过闭包让局部变量驻留在内存中
function fun(){
var arr=[];
for(var i=0; i<5; i++){
arr[i]=function(n){
return function(){
return '元素'+n;
}
}(i)
}
return arr
}
var Bb=fun()
//alert(Bb.length)
// alert(Bb[0]())
for(var i=0; i<5; i++){
//alert(Bb[i])
alert(Bb[i]())
}
//这次成功的输出了 ‘元素0 元素1 元素2 元素3 元素4 ’,而不再都是[元素5]
/*
1.这里的匿名函数有一个参数 n,也就是最终将返回的结果数值;
2.在调用每个匿名函数时传入变量i
3.变量i的当前值会赋值给n,
4.匿名函数内部创建并返回了一个访问n的闭包
5.如此数组arr中的每个函数中都有了自己的n变量的一个副本(闭包可以将局部变量贮存在内存中) */
闭包的相关知识点
- 常见的方式是在函数内部创建另一个函数
- 闭包的第一个用途:通过闭包可以访问局部变量
- 闭包的第二个用途:可以让局部变量的值始终保持在内存中
- 优点:可以把局部变量驻留在内存中,可以避免使用全局变量;
全局变量在复杂程序中会造成许多麻烦(比如命名冲突,垃圾回收等),所以推荐使用私有的,封装的局部变量。而闭包可以实现这一点。
- 缺点:由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存;所以过度使用闭包会导致性能下降;
- 优点:可以把局部变量驻留在内存中,可以避免使用全局变量;
- 循环函数中的匿名函数和闭包问题
12、js匿名函数中的this指代的是谁?
window
闭包中的this问题
- 之前的课程中讲过this是在运行时基于函数的执行环境来绑定的
- 全局函数中的this是window,而当函数作为某个对象的方法调用时,this就是指的那个对象......
- 匿名函数的执行环境具有全局性,this通常是指向window的。
- 可以使用对象冒充强制改变this的指向
- 将this赋值给一个变量,闭包访问这个变量
var name='The Window';
var obj={
name:'my obj',
get:function(){
return function(){
return this.name;
}
}
} alert(obj.get()()) //这次返回的是全局变量 'The Window'
13、如何让匿名函数中的this指向当前对象?
对象冒充 闭包访问
匿名函数的执行环境具有全局性,this通常是指向window的。
- 可以使用对象冒充强制改变this的指向
- 将this赋值给一个变量,闭包访问这个变量
对象冒充
var name='The Window';
var obj={
name:'my obj',
get:function(){
return function(){
return this.name;
}
}
} alert(obj.get()()) //这次返回的是全局变量 'The Window'
alert(obj.get().call(obj))//这次又返回的是'my obj',因为call()强制改变了this的指向
闭包访问
var name='The Window';
var obj={
name:'my obj',
get:function(){
//这里的this指的是对象,这里为obj
var self=this
return function(){
//闭包里的this指的是window
return self.name;
}
}
} alert(obj.get()())
14、如何模仿块级作用域?
立即执行 匿名函数
用匿名函数
将需要放进块级作用域的东西放进一个立即执行的匿名函数里面
js没有块级作用域代码
function myfun() { for(var i=0;i<5;i++){ } //i不会因为离开了for块就失效; var i; //重新声明后i还是5, alert(i) //此时的i=5
}
模仿块级作用域
<script>
//模仿块级作用域
function myfun() { (function(){
for(var i=0;i<5;i++){
alert(i)
}
})() // 这里定义并立即调用了一个匿名函数; alert(i)
//此时的i已结不存在 会报错:'i is not defined'
}
myfun()
</script>
块级作用域又叫私有作用域,但是JS没有块级作用域的概念;这意味着在块语句(比如for语句)中定义的变量,不会因为离开了for块就失效。
- 使用了块级作用域后,匿名函数中定义的任何变量,都会在执行结束时被销毁;
- 一般来说,我们都应该尽可能少向全局作用域中添加变量和函数;过多的全局变量和函数很容易导致命名冲突
- 使用块级作用域,每个开发者既可以使用自己的变量,又不必担心搞乱全局作用域;
- 在全局作用域中使用块级作用域可以减少闭包占用的内存问题.
15、js对象如何创建私有变量和类似其它语言的get、set方法(特权方法)?
私有变量 对象 private 权限
特权方法 this 属性 匿名方法
this方式定义的变量方法外部可以访问
var方式定义的吧变量方法外部无法访问
私有变量也就是例如java对象的private权限的变量
var name='张三'; // 私有变量;
特权方法其实是this的一个属性,这个属性指向一个匿名方法,因为是当前对象的属性,所以外部可以访问
this.getname=function(){ // 对外公共的特权方法;
return name;
}
私有变量
JavaScript没用私有属性的概念;所有的属性都是公用的;
私有变量的概念:在任何函数中定义的变量,都是私有变量,因为不能在函数外部访问这些变量;
- 私有变量:包括函数的参数/局部变量和在函数内部定义的其他函数;
- 特权方法:内部创建一个闭包,闭包可以访问私有变量;因此创建用于访问私有变量的公用方法,称作特权方法
- 可以通过构造方法传参来访问私有变量
这种方法的缺点是会为每一个实例创建一组新的方法,不能实现共享。
function People(){
var name='张三'; // 私有变量;
var age='30';
function say(){ // 私有函数;
return '我是......';
} this.getname=function(){ // 对外公共的特权方法;
return name;
} this.getsay=function(){
return say()
}
}
var p=new People()
alert(p.getname())
alert(p.getsay())
16、对象创建的时候,用this声明的属性和用var定义的局部变量创建的对象是不同的?
this 属性 访问 变量 public 权限
var 函数变量 无法访问 变量 private 权限
使用this方式的话是对象的属性,外部可以轻松访问变量,相对于java中给变量设置权限public
使用var方式的话,是函数变量(局部变量,私有变量),函数外部无法访问,相对于java中非变量设置private权限,使用特权方法可以访问,特权方法相对于get/set方法,
使用this方式
function People(){
this.name='张三';
this.age='30';
this.say=function (){
return '我是'+this.name+'......';
}
}
使用var方式
function People(){
var name='张三'; // 私有变量;
var age='30';
function say(){ // 私有函数;
return '我是......';
} this.getname=function(){ // 对外公共的特权方法;
return name;
} this.getsay=function(){
return say()
}
}
17、js对象如何创建静态变量(静态私有变量)?
立即执行的闭包 原型 特权方法 块级作用域
静态私有变量
通过块级作用域(私有作用域)中定义私有变量或函数,创建对外公共的特权方法;
- 首先创建私有作用域
- 定义私有变量或函数
- 定义构造函数和特权方法
- 这种方式创建的私有变量因为使用原型而实现共享。
- 同时由于共享,实例也就没有自己的私有变量。
(function(){
var name='张三';
User=function(){} //构造函数
User.prototype.getName=function(){
return name
}
User.prototype.setName=function(value){
name=value
};
})() var VIP1=new User() //因为Uer()是私有函数,所以外部无法访问。
//alert(VIP1.getName())
VIP1.setName('李四')
//alert(VIP1.getName()) var VIP2=new User()
alert(VIP2.getName())
18、js对象为何会用到静态私有变量(静态方法)?
共享
共享肯定是要通过原型的
私有变量方式的缺点是会为每一个实例创建一组新的方法,不能实现共享。
19、下面代码是匿名函数么?
函数 名字
get:function(){
return this.name;
}
}
这只是json写法的对象中的函数而已,就是讲函数赋值给一个变量,这个函数是有名字的,所以不叫闭包
get:function(){
return function(){
return this.name;
}
}
这个才是闭包
这个不是
var obj={
name:'my obj',
get:function(){
return this.name;
}
}
alert(obj.get()) //返回 'my obj'
这个是
var name='The Window';
var obj={
name:'my obj',
get:function(){
return function(){
return this.name;
}
}
} alert(obj.get()()) //这次返回的是全局变量 'The Window'
alert(obj.get().call(obj))//这次又返回的是'my obj',因为call()强制改变了this的指向
二、内容在总结中
js匿名函数和闭包总结的更多相关文章
- js匿名函数与闭包作用
http://www.jb51.net/article/79238.htm 1 闭包允许内层函数引用父函数中的变量,但是该变量是最终值 当mouseover事件调用监听函数时,首先在匿名函数( fun ...
- js匿名函数,闭包
http://www.cnblogs.com/chenxianbin89/archive/2010/01/28/1658392.html
- js循环函数中的匿名函数和闭包问题(匿名函数要用循环中变量的问题)
js循环函数中的匿名函数和闭包问题(匿名函数要用循环中变量的问题) 一.总结 需要好好看下面代码 本质是因为匿名函数用到了循环中的变量,而普通方式访问的话,匿名函数的访问在循环之后,所以得到的i是循环 ...
- JS匿名函数的理解
js匿名函数的代码如下:(function(){ // 这里忽略jQuery 所有实现 })(); 半年前初次接触jQuery 的时候,我也像其他人一样很兴奋地想看看源码是什么样的.然而,在看到源码的 ...
- php的匿名函数和闭包函数
php的匿名函数和闭包函数 tags: 匿名函数 闭包函数 php闭包函数 php匿名函数 function use 引言:匿名函数和闭包函数都不是特别高深的知识,但是很多刚入门的朋友却总是很困惑,因 ...
- 匿名函数、闭包、lambda表达式、Block
C#有lambda.匿名函数,js有匿名函数.闭包,OC中有block,看到这是不是心中有一万个草泥马在跑,不过它们这些都是换汤不换药,不同语言名字不一样. 从功能性上说lambda和closure( ...
- javascript进阶课程--第三章--匿名函数和闭包
javascript进阶课程--第三章--匿名函数和闭包 一.总结 二.学习要点 掌握匿名函数和闭包的应用 三.匿名函数和闭包 匿名函数 没有函数名字的函数 单独的匿名函数是无法运行和调用的 可以把匿 ...
- js匿名函数测试
js匿名函数测试 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> < ...
- JS匿名函数自执行函数
JS匿名函数自执行函数:(function(){})();(function(){}) 这是一个函数,函数后面接(),则是调用函数 比如(function(arg){console.log(arg); ...
随机推荐
- Kintone学习
kintone JavaScript编码指南 编码的注意地方: 文字编码 使用 utf-8
- 2018-2019-2 20165209 《网络对抗技术》Exp7: 网络欺诈防范
2018-2019-2 20165209 <网络对抗技术>Exp7: 网络欺诈防范 1 基础问题回答和实验内容 1.1基础问题回答 (1)通常在什么场景下容易受到DNS spoof攻击. ...
- 基于webview的Hybrid app和React Native及html5
基于webview的Hybrid app和React Native及html5 React Native 结合了 Web 应用和 Native 应用的优势,可以使用 JavaScript 来开发 iO ...
- 20145322 Exp5 Adobe阅读器漏洞攻击
20145322 Exp5 Adobe阅读器漏洞攻击 实验过程 IP:kali:192.168.1.102 windowsxp :192.168.1.119 msfconsole进入控制台 使用命令为 ...
- 实验二 Java 面向对象程序设计
实验内容 1 初步掌握单元测试和TDD 2 理解并掌握面向对象三要素:封面,继承,多态 3 初步掌握UML建模 4 熟悉SOLID原则 5 了解设计模式 (一)单元测试 D
- Codeforces Round#413 Problem A - C
Problem#A Carrot Cakes vjudge链接[here] (偷个懒,cf链接就不给了) 题目大意是说,烤面包,给出一段时间内可以考的面包数,建第二个炉子的时间,需要达到的面包数,问建 ...
- 主引导记录MBR的结构和作用
MBR磁盘分区都有一个引导扇区,称为主引导记录,英文简称为MBR.1. MBR的结构MBR扇区位于整个硬盘的第一个扇区:按照C/H/S地址描述,即0柱面〇磁头1扇 区:按照LBA地址描述即0扇区.它是 ...
- 精巧好用的DelayQueue 转
我们谈一下实际的场景吧.我们在开发中,有如下场景 a) 关闭空闲连接.服务器中,有很多客户端的连接,空闲一段时间之后需要关闭之.b) 缓存.缓存中的对象,超过了空闲时间,需要从缓存中移出.c) 任务超 ...
- com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input
作者原创,转载请注明转载地址 第一次遇到该异常,在网上搜了很长时间也没找到解决答案,特此记录 1.异常展示: com.fasterxml.jackson.databind.JsonMappingExc ...
- 解决复制到keil编辑器中汉字出现乱码情况
https://blog.csdn.net/dxuehui/article/details/51123372 1.在菜单栏中选择'Edit'选项. 2.'Edit'选项中选择'Configuratio ...