匿名函数与闭包

  • 匿名函数
  • 闭包
    • 概念
    • 相关知识点
    • 闭包中的this
  • 循环函数中的匿名函数和闭包
    • 循环函数中的匿名函数
    • 循环函数中的闭包
  • 模仿块级作用域
  • 私有变量
  • 静态私有变量

匿名函数

没有函数名的函数

  • 单独的匿名函数是无法运行和调用的
  • 可以把匿名函数赋值给变量
  • 通过表达式自我执行,语法:(匿名函数)();
  • 匿名函数传递参数,语法:(匿名函数)(参数);
    <script>// 普通函数function func1(){alert("我是普通函数");}// func1();// 匿名函数// function(){//     alert("我是匿名函数");// }// 将匿名函数赋值给变量// var myfunc = function (){//     alert("我是匿名函数2");// }// alert(myfunc);//将函数表达式输出// myfunc();//运行匿名函数// 匿名函数通过表达式自我执行(function(name, age){alert("匿名函数自我执行")})();// 匿名函数传递参数(function(name, age){alert(name + "今年" + age + "岁")})("OliGit", 23);</script>

闭包

概念

  • 闭包的英文单词是closure,是指有权访问另一个函数作用域中变量的函数
  • 在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。内层的函数可以使用外层函数的所有变量,即使外层函数执行完毕
  • 这是JavaScript中非常重要的一部分知识,因为使用闭包可以大大减少我们的代码量,使我们的代码看起来更加清晰等等,总之功能十分强大

相关知识点

  • 常见的方式是在函数内部创建另一个函数
   function myfunc(){return function(){return("***********");}}// alert(myfunc);//输出整个函数表达式// alert(myfunc());//输出匿名函数表达式// 调用闭包方式1// alert(myfunc()());//输出匿名函数返回值//调用闭包方式2var bb = myfunc();alert(bb());
  • 闭包的第一个用途:通过闭包可以访问局部变量
   // 通过闭包访问局部变量function func(){var jb = "局部变量";}// alert(jb);//函数外无法访问函数内的局部变量function func2(){var jb2 = "局部变量2";return function(){return(jb2);//通过匿名函数返回func2()的局部变量jb2}}// 调用方式1// alert(func2()());// 调用方式2var JB2 = func2();alert(JB2());
  • 闭包的第二个用途:可以让这些变量的值始终保持在内存中
    1、忧点:可以把局部变量驻留在内存中,可以避免使用全局变量;(全局变量在复杂程序中会造成许多麻烦(比如命名冲突,垃圾回收等),所以推荐使用私有的封装的局部变量。而闭包可以实现这一点)
    2、缺点:由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存;所以过度使用闭包会导致性能下降
   var num = 100;//全局变量function add(){alert(++num);}// add();// add();// add();//每执行函数一次,num累加一次function add2(){var num2 = 100;//局部变量alert(++num2);}//每调用一次初始化局部变量一次,所以无法实现累加// add2();add2();add2();//通过闭包实现局部变量的累加function add3(){var num3 = 100;//局部变量return function(){alert(++num3);}}// 调用方式1:无法实现累加,因为每次调用num3都会初始化一次,// 这是因为每一次都是重新调用函数到结束,再重新调用一次,所以num3都会初始化一次// add3()();add3()();add()();//101// 调用方式2:可以实现累加,因为外部函数add3只执行一次,即num3只初始化一次//后面执行三次的都是匿名函数,而匿名函数没有初始化num3,所以可是实现累加var ADD3 = add3();//这里只初始化一次ADD3();ADD3();ADD3();//101,102,103ADD3 = null;//最后赋值为空,及时解除引用,否则会占用更多内存

闭包中的this

匿名函数的执行环境具有全局性,this通常是指向window的

  • 可以使用对象冒充强制改变this的指向
  • 将this赋值给一个变量,闭包访问这个变量
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>闭包中的this</title>
</head>
<body><script>var name = "The Window";var obj1 = new Object();obj1.name = "The Object";obj1.getName = function(){return this.name;}// alert(obj1.getName());//返回The Objectvar obj2 = {name : "The Object2",getName: function(){return this.name;}}// 属性的函数内// alert(obj2.getName());//返回The Object2// 闭包里的this/var obj3 = {name : "The Object3",getName : function(){return function(){// 匿名函数的执行环境具有全局性,this通常是指向window的return this.name;}}}// alert(obj3.getName()());//返回The Window// 如果想访问属性name// 方法一:可以使用对象冒充call()强制改变this的指向// alert(obj3.getName().call(obj3));//返回The Window// 方法二:将this赋值给一个变量,闭包访问这个变量var obj4 = {name : "The Object4",getName : function(){//返回的值object对象,属性方法this指向object,也可以看最上面的2个例子// alert(this);// 所以可以在属性方法里将this赋值给一个变量,然后匿名函数访问这个变量即可var self = this;//this指向Object对象return function(){// 闭包函数可以向上访问父函数的属性return self.name;}}}alert(obj4.getName()());</script>
</body>
</html>

循环函数中的匿名函数和闭包

循环函数中的匿名函数

        function func1(){var arr = [];for (var i = 0; i < 5; i++){arr[i] = "元素" + i;}return(arr);}// alert(func1());//元素0,元素1,元素2,元素3,元素4//循环里包含匿名函数function func2(){var arr2 = [];for (var i = 0; i < 5; i++){arr2[i] = function(){return "元素" + i;};//此时匿名函数没有执行,里面的i为参数}return(arr2);//此时arr2数组内5个空间都为匿名函数}// alert(func2());//输出一个包含五个匿名函数的数组,证明匿名函数没有执行//function(){ return "元素" + i; },//function(){ return "元素" + i; },//function(){ return "元素" + i; },//function(){ return "元素" + i; },//function(){ return "元素" + i; }var Bb = func2();//循环已经结束,此时的i已经变成5,当调用里面的// 匿名函数时,将i = 5 传入匿名函数内// alert(Bb[0]);   alert(Bb[1]); //function(){ return "元素" + i; }// alert(Bb[0]());     alert(Bb[1]()); //元素5, 元素5// for (var i = 0; i < 5; i++){//     alert(Bb[i]());//全是元素5,没有得到想要的结果// }// 让匿名函数立刻执行赋值function func3(){var arr3 = [];for (var i = 0; i < 5; i++){arr3[i] = (function(){return "元素" + i;})()//匿名函数立刻执行}return arr3;//此时arr3数组内得到的为匿名函数的返回值}var Bb3 = func3();// alert(Bb3.length);//5// alert(Bb3);//元素0,元素1,元素2,元素3,元素4// alert(Bb3[0]);//元素0

循环函数中的闭包

        function func4(){var arr4 = [];for (var i = 0; i < 5; i++){arr4[i] = (function(n){return function(){return "元素" + n;}})(i)}return arr4;}var Bb4 = func4();// alert(Bb4.length);//5for (var i = 0; i < 5; i++){// alert(Bb4[i]);alert(Bb4[i]());//成功输出元素0-4}

模仿块级作用域

块级作用域又叫私有作用域,单数JS没有块级作用域的概念;这意味着在块语句(比如for语句)中定义的变量,不会因为离开了for语句后就失效

  • 使用了块级作用域后,匿名函数中定义的任何变量,都会在执行结束时被销毁
  • 一般来说,我们都应该尽可能少向全局作用域中添加变量和函数;过多的全局变量和函数很容易导致命名冲突
  • 使用块级作用域,每个开发者既可以使用自己的变量,又不担心搞乱全局作用域
  • 在全局作用域中使用块级作用域可以减少闭包占用内存问题
function func(){for (var i = 0; i < 5; i++){// i不会因为离开了for语句就失效}var i;//即使重新声明一个i变量,结果还是5alert(i);//i输出5}// func();// 模仿块级作用域function func2(){(function(){for (var i = 0; i < 5; i++){}})()alert(i);//此时的i已经不存在,会报错:"i is not defined"}func2();

私有变量

JavaScript没有私有属性概念;所有的属性都是公用的
私有变量的概念:在任何函数中定义的变量,都是私有变量,因为不能在函数外部访问这些变量

  • 私有变量:包括函数的参数、局部变量和函数内部定义的其他函数
  • 特权方法:内部创建一个闭包,闭包可以访问私有变量;因此创建用于访问私有变量的公用方法,称作特权方法
  • 可以通过构造方法传参来访问私有变量(这种方法的缺点是会为每一个实例创建一组新的方法,不能实现共享)
    <script>function sum(){var m = 100;}// alert(m);//会报错,私有变量(局部变量),外部无法访问function people(){this.name = "OliGit";this.say = function(){return "我是" + this.name;}}// var pson = new people();// alert(pson.name);//OliGit// alert(pson.say());//我是OliGitfunction people2(){var name = "OliGit";//私有变量function say(){//私有方法、函数return "我是" + name;}this.getName = function(){return name;}this.getSay = function(){return say();}}var pson2 = new people2();// alert(pson2.name);//undefined// alert(pson2.age);//undefined// alert(pson2.say());//say is not a functionalert(pson2.getName());//OliGitalert(pson2.getSay());//我是OliGit// 通过构造方法传参来访问私有变量function people3(_name){var name = _name;this.getName =  function(){return name;}this.setName = function(value){name = value;}}var pson3 = new people3("OliGit");alert(pson3.getName());pson3.setName("奥利给");alert(pson3.getName());</script>

静态私有变量

通过块级作用域(私有作用域)中定义私有变量或函数,创建对外公共的特权方法

  • 首先创建私有作用域
  • 定义私有变量或函数
  • 定义构造函数和特权方法
  • 这种方式创建的私有变量因为使用原型而实现共享
  • 同时由于共享,实例也就没有自己的私有变量
    <script>(function(){var name = "OliGit";User = function(){}// 构造函数User.prototype.getName = function(){return name;}User.prototype.setName = function(value){name = value;}})()var VIP1 = new User();// alert(VIP1.getName());VIP1.setName("Olivia");alert(VIP1.getName());//Oliviavar VIP2 = new User();alert(VIP2.getName());//Olivia</script>

JavaScript 匿名函数与闭包相关推荐

  1. JavaScript匿名函数和闭包

    概述 在JavaScript前端开发中,函数与对其状态即词法环境(lexical environment)的引用共同构成闭包(closure).也就是说,闭包可以让你从内部函数访问外部函数作用域.在J ...

  2. javascript匿名函数及闭包深入理解及应用

    1.匿名函数 函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没有函数名的函数. 1.1 函数的定义,首先简单介绍一下函数的定义,大致可分为三种方式 第一种: ...

  3. javascript进阶课程--第三章--匿名函数和闭包

    javascript进阶课程--第三章--匿名函数和闭包 一.总结 二.学习要点 掌握匿名函数和闭包的应用 三.匿名函数和闭包 匿名函数 没有函数名字的函数 单独的匿名函数是无法运行和调用的 可以把匿 ...

  4. php的匿名函数和闭包函数

    php的匿名函数和闭包函数 tags: 匿名函数 闭包函数 php闭包函数 php匿名函数 function use 引言:匿名函数和闭包函数都不是特别高深的知识,但是很多刚入门的朋友却总是很困惑,因 ...

  5. 简单介绍Javascript匿名函数和面向对象编程

    忙里偷闲,简单介绍一下Javascript中匿名函数和闭包函数以及面向对象编程.首先简单介绍一下Javascript中的密名函数. 在Javascript中函数有以下3中定义方式: 1.最常用的定义方 ...

  6. js 匿名函数和闭包

    匿名函数和闭包 转https://www.cnblogs.com/xiaowie/p/10277483.html 填写了注释 匿名函数就是没有名字的函数,闭包是可访问一个函数作用域里变量的函数.声明: ...

  7. html 匿名函数调用,浅析Javascript匿名函数与自执行函数

    函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没有函数名的函数. 函数的定义,大致可分为三种方式: 第一种:这也是最常规的一种 function doubl ...

  8. javascript匿名函数的理解

    复制粘贴 [color=red]点评:请记住,关键点是理解javascript的函数概念(参考w3cshool对函数的描述,搜索关键字:ECMAScript 函数).以及()的运算的理解. 比如:va ...

  9. 深入理解Java Lambda表达式,匿名函数,闭包

    前言 对于Lambda表达式一直是知其然不知其所以然,为了搞清楚什么是Lambda表达式,以及Lambda表达式的用法和作用,本文应运而生当做学习笔记分享出来,欢迎指正交流. 什么是Lambda 让我 ...

最新文章

  1. Java知识点26——模拟12306买票过程、模拟龟兔赛跑的过程、静态代理例子
  2. 对request.getSession(false)的理解(附程序员常疏忽的一个漏洞)--转
  3. 假设有50瓶饮料,喝完3个空瓶可以换一瓶饮料,依次类推,请问总共喝了多少瓶饮料???
  4. matlab 邵玉斌,matlab 清华大学出版社 邵玉斌编写的《通信系统建模与仿真实例分析》一书的所有MATLAB和SIMULINK代码 - 下载 - 搜珍网...
  5. java_day19_MVC和配置文件
  6. linux内存一直占满问题
  7. WebService调用
  8. JSpider(4):Tasks,EventsVisitors
  9. Android版MrHuo工作室客户端开发心得(二)
  10. K8s 使用helm 安装 EFK和ELK分布式日志分析系统系列(es版本:6.7.0;)
  11. 路由器和交换机的转发过程
  12. 网页中无法直接关注微信公众号怎么办?一键唤起微信关注公众号的解决方案
  13. 查询计算机网络凭据,查看电脑账密利器 - 电脑凭据管理器图文使用教程
  14. CAD如何调整线形比例?
  15. 定义python函数时如果函数中没有return语句_定义Python函数时,如果函数中没有return语句,则默认返回空值None。...
  16. Qt - 驾校科目-考试系统-窗口交互
  17. 2022年湖北省大学生电子设计竞赛A题(单项交流电子负载)赛后总结
  18. java socket解决半包、粘包问题
  19. 【贝叶斯分析①】Metropolis-Hastings算法理解和简单实现
  20. ftp yum 安装软件报错FTP Error 550 - Server denied you to change to the given directory

热门文章

  1. mysql 查询两张表结构相同的数据库_数据库原理习题(含答案)
  2. 十大经典排序算法详细总结 图形展示 代码示例
  3. 一年月份大小月口诀_怀胎十月,为啥我只能算出9个月?
  4. Angular.js学习-入门
  5. BZOJ5243 : [Lydsy2017省队十连测]绝版题
  6. K-means算法应用:图片压缩
  7. mac 显示隐藏文件的命令行和快捷键
  8. 买无线路由还是买无线AP?
  9. Flutter PageView 实现的自动轮播图效果 Timer实现的自动轮播效果
  10. Mr.J-- jQuery学习笔记(十三)--选项Tab卡