js匿名函数和闭包总结

时间:2023-03-09 17:10:27
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)

匿名函数

没有函数名字的函数

  1. 单独的匿名函数是无法运行和调用的
  2. 可以把匿名函数赋值给变量
  3. 通过表达式自我执行,语法:(匿名函数)()
  4. 匿名函数传递参数,语法:(匿名函数)(参数)

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、闭包的用途是什么?

局部变量 常驻内存

闭包的相关知识点

  1. 常见的方式是在函数内部创建另一个函数
  2. 闭包的第一个用途:通过闭包可以访问局部变量
  3. 闭包的第二个用途:可以让局部变量的值始终保持在内存中
    • 优点:可以把局部变量驻留在内存中,可以避免使用全局变量;

      全局变量在复杂程序中会造成许多麻烦(比如命名冲突,垃圾回收等),所以推荐使用私有的,封装的局部变量。而闭包可以实现这一点。

    • 缺点:由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存;所以过度使用闭包会导致性能下降;
  4. 循环函数中的匿名函数和闭包问题

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 //应及时解除引用,否则会占用更多存

闭包的相关知识点

  1. 常见的方式是在函数内部创建另一个函数
  2. 闭包的第一个用途:通过闭包可以访问局部变量
  3. 闭包的第二个用途:可以让局部变量的值始终保持在内存中
    • 优点:可以把局部变量驻留在内存中,可以避免使用全局变量;

      全局变量在复杂程序中会造成许多麻烦(比如命名冲突,垃圾回收等),所以推荐使用私有的,封装的局部变量。而闭包可以实现这一点。

    • 缺点:由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存;所以过度使用闭包会导致性能下降;
  4. 循环函数中的匿名函数和闭包问题
  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变量的一个副本(闭包可以将局部变量贮存在内存中) */

闭包的相关知识点

  1. 常见的方式是在函数内部创建另一个函数
  2. 闭包的第一个用途:通过闭包可以访问局部变量
  3. 闭包的第二个用途:可以让局部变量的值始终保持在内存中
    • 优点:可以把局部变量驻留在内存中,可以避免使用全局变量;

      全局变量在复杂程序中会造成许多麻烦(比如命名冲突,垃圾回收等),所以推荐使用私有的,封装的局部变量。而闭包可以实现这一点。

    • 缺点:由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存;所以过度使用闭包会导致性能下降;
  4. 循环函数中的匿名函数和闭包问题

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的指向

二、内容在总结中