JavaScript基础篇(6)之函数表达式闭包


Posted in Javascript onDecember 11, 2015

 其实js支持函数闭包的主要原因是因为js需要函数能够保存数据。这里的保存数据是只函数在运行结束以后函数内变量的值也会进行保存。至于为什么js需要在函数内可以保存数据,那就是js是一种函数式语言。在函数内保存数据是函数式语言的一大特征。

回顾前面介绍过的三种定义函数方式

functiosu(numnumreturnunum//函数声明语法定义
vasufunction(numnum)returnunum}//函数表达式定义
vasuneFunction("num""num""returnunum")//Functio构造函数

在分析闭包之前我们先来看看,定义和调用函数容易犯的错误。

例1:

sayHi(); //错误:函数还不存在
var sayHi = function () {
  alert("test");
};

例2:

if (true) {
  function sayHi() {
    alert("1");
  }
} else {
  function sayHi() {
    alert("2");
  }
}
sayHi();//打印结果并不是我们想要的

例3:

var fun1 = function fun2() {
  alert("test");
}
fun2();//错误:函数还不存在

在例1中,我们不能在使用函数声明式语法定义之前调用函数。解决方案:

1.如果使用函数表达式定义函数的话,需要在表达式定义后调用。

var sayHi = function () {
  alert("test");
};
sayHi()

2.使用函数声明式。(这里浏览器引擎会 函数声明提升, 在所有代码执行之前先读取函数声明)

sayHi(); 
function sayHi () {
  alert("test");
};

在例2中,我们预期的结果应该是打印1,实际结果是打印2。

if (true) {
  function sayHi() {
   alert("1");
  }
  } else {
  function sayHi() {
   alert("2");
  }
}
sayHi();//打印结果并不是我们想要的

为什么会这样?正因为 函数声明提升 ,所以浏览器在预解析的时候不会判断if条件,直接解析第二个函数定义的时候覆盖了第一个。

解决方案:

var sayHi;
if (true) {
  sayHi = function () {
   alert("1");
  }
  } else {
  sayHi = function () {
   alert("2");
  }
}
sayHi();

在例3中,发现只能只用fun1()调用,而不能使用fun2()调用。

我自己的理解,真正原因不知道。没找到资料。

因为1: function fun3() { }; 等效与  var fun3 = function fun3() { }; 如图:

JavaScript基础篇(6)之函数表达式闭包 

所以只能只用fun1()调用,而不能使用fun2()调用。

其实这里我还是有疑问的?哪位大神知道,望告知。

既然,fun2在外面不能调用为什么在函数内部能调用?虽然在debugger还是得不到fun1。

JavaScript基础篇(6)之函数表达式闭包 

好了,通过上面的三道题目热身。我们继续今天的主题“闭包”。

1.什么是闭包?

定义:就是有权访问另一个函数作用域的变量的函数

我们先从一个示例函数开始:

例1:

function fun() {
  var a = "张三";
}
fun();//在我们执行完后,变量a就被标记为销毁了

例2:

function fun() {
  var a = "张三";
  return function () {
    alert("test");
  }
}
var f = fun();//同样,在我们执行完后,变量a就被标记为销毁了

例3:

function fun() {
  var a = "张三";
  return function () {
    alert(a);
  }
}
var f = fun();//【现在情况发生变化了,如果a被销毁,显然f被调用的话就不能访问到变量a的值了】
f();//【然后变量a的值正常的被访问到了】
//这就是闭包,当函数A 返回的函数B 里面使用到了函数A的变量,那么函数B就使用了闭包。
示例:
function fun() {
  var a = "张三";
  return function () {
   alert(a);
  }
}
var f = fun();//【现在情况发生变化了,如果a被销毁,显然f被调用的话就不能访问到变量a的值了】
f();//【然后变量a的值正常的被访问到了】

显然,滥用闭包会增大内存的使用。所以非特殊情况尽量不要使用闭包。如果用到了,记得手动设置空引用,内存才能被回收 f = null ;

图解:(不了解作用域链的同学请先看前面的文章 作用域和作用域链 )

JavaScript基础篇(6)之函数表达式闭包 

2.什么是匿名函数? (仅仅只是解释这个概念)

如:(即,没有名字的函数)

JavaScript基础篇(6)之函数表达式闭包 

关于对象中函数的返回值是匿名函数时,this的怪异现象

讲解之前,先清醒下头脑,不要越看越迷糊了。如果迷糊了,那就直接忽略下面的。

var name1 = "张三";
var obj = {
  name1: "李四",      
  fun2: function () {
    alert(this.name1);
  },
  fun3: function () {
    return function () {
      alert(this.name1);
    }
  }
}

obj.fun2();//打印结果"李四"意料之中的。
obj.fun3()();//因为这里返回的是一个函数,所以要再加一对()来调用。打印结果是"张三",意料之外。
//真是百事不得其解啊,什么this指向了全局?
我们前面讲过“ 哪个对象点出来的方法,this就是哪个对象 ”,那我们的  obj.fun3()() 打印的是“张三”也就是说this执行了全局作用域。

我们看看下面的示例也许就知道为什么了。

var name1 = "张三";
var obj = {
  name1: "李四",      
  fun2: function () {
    alert(this.name1);
  },
  fun3: function () {
    return function () {
      alert(this.name1);
    }
  }
}    
//obj.fun3()();
var obj2 = {};
obj2.name1 = "test";
obj2.fun = obj.fun3();
obj2.fun();//打印结果"test",再次证明了“哪个对象点出来的方法,this就是哪个对象”.
var name1 = "张三";
var obj = {
  name1: "李四",
  fun2: function () {
   alert(this.name1);
  },
  fun3: function () {
    return function () {
     alert(this.name1);
    }
  }
}
//obj.fun3()();
var obj2 = {};
obj2.name1 = "test";
obj2.fun = obj.fun3();
obj2.fun();//打印结果"test",再次证明了“哪个对象点出来的方法,this就是哪个对象”.

我们来分解下 obj.fun3()() 先是  obj.fun3() 返回一个匿名函数到了window作用域,然后接着调用this就指向了window了。( 感觉解释有点勉强,也不知道对不,暂时自己先是这么理解的 )

闭包形成的原因:内存释放问题

一般,当函数执行完毕后,局部活动对象会被销毁,内存中仅保存全局作用域,但闭包的情况是不一样的。

闭包的活动对象依然会保存在内存中,于是像上例中,函数调用返回后,变量i是属于活动对象里面的,就是说其栈区还没有释放,但你调用c()的时候i变量保存的作用域链从b()->a()->全局去寻找作用域var i声明所在,然后找到了var i=1;然后在闭包内++i;结果,最后输出的值就是2了;

以上所述是小编给大家分享的JavaScript基础篇(6)之函数表达式闭包,希望大家喜欢。

Javascript 相关文章推荐
JS弹出层单纯的绝对定位居中示例代码
Feb 18 Javascript
javascript中clone对象详解
Dec 03 Javascript
详解AngularJS中的filter过滤器用法
Jan 04 Javascript
js canvas实现擦除动画
Jul 16 Javascript
jQuery Dialog 取消右上角删除按钮事件
Sep 07 Javascript
微信开发 微信授权详解
Oct 21 Javascript
ES6新数据结构Map功能与用法示例
Mar 31 Javascript
vue 解决addRoutes动态添加路由后刷新失效问题
Jul 02 Javascript
vue实现word,pdf文件的导出功能
Jul 31 Javascript
jdk1.8+vue elementui实现多级菜单功能
Sep 24 Javascript
详解VUE中的插值( Interpolation)语法
Oct 18 Javascript
jquery实现异步文件上传ajaxfileupload.js
Oct 23 jQuery
jQuery弹簧插件编写基础之“又见弹窗”
Dec 11 #Javascript
jQuery点击改变class并toggle及toggleClass()方法定义用法
Dec 11 #Javascript
Express实现前端后端通信上传图片之存储数据库(mysql)傻瓜式教程(二)
Dec 10 #Javascript
Express的路由详解
Dec 10 #Javascript
在 Express 中使用模板引擎
Dec 10 #Javascript
Express实现前端后端通信上传图片之存储数据库(mysql)傻瓜式教程(一)
Dec 10 #Javascript
基于jQuery实现复选框是否选中进行答题提示
Dec 10 #Javascript
You might like
PHP模板解析类实例
2015/07/09 PHP
Laravel框架执行原生SQL语句及使用paginate分页的方法
2018/08/17 PHP
PHP按符号截取字符串的指定部分的实现方法
2018/09/10 PHP
Sample script that deletes a SQL Server database
2007/06/16 Javascript
20款超赞的jQuery插件 Web开发人员必备
2011/02/26 Javascript
JS小功能(列表页面隔行变色)简单实现
2013/11/28 Javascript
JavaScript对IE操作的经典代码(推荐)
2014/03/10 Javascript
动态创建script在IE中缓存js文件时导致编码的解决方法
2014/05/04 Javascript
Jquery中find与each方法用法实例
2015/02/04 Javascript
基于javascript实现右下角浮动广告效果
2016/01/08 Javascript
JavaScript高级程序设计(第三版)学习笔记6、7章
2016/03/11 Javascript
jQuery+ajax实现实用的点赞插件代码
2016/07/06 Javascript
js接收并转化Java中的数组对象的方法
2016/08/11 Javascript
使用Vue-cli 3.0搭建Vue项目的方法
2018/06/07 Javascript
vscode下vue项目中eslint的使用方法
2019/01/13 Javascript
Vue.js样式动态绑定实现小结
2019/01/24 Javascript
vue 框架下自定义滚动条(easyscroll)实现方法
2019/08/29 Javascript
vue.js+elementUI实现点击左右箭头切换头像功能(类似轮播图效果)
2019/09/05 Javascript
[25:59]Newbee vs TNC 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
python实现字符串连接的三种方法及其效率、适用场景详解
2017/01/13 Python
Python随机生成均匀分布在三角形内或者任意多边形内的点
2017/12/14 Python
浅谈python中str字符串和unicode对象字符串的拼接问题
2018/12/04 Python
通过python实现弹窗广告拦截过程详解
2019/07/10 Python
Python如何基于selenium实现自动登录博客园
2019/12/16 Python
基于Tensorflow批量数据的输入实现方式
2020/02/05 Python
解决pytorch-yolov3 train 报错的问题
2020/02/18 Python
python设置中文界面实例方法
2020/10/27 Python
Django缓存Cache使用详解
2020/11/30 Python
CSS3解析抖音LOGO制作的方法步骤
2019/04/11 HTML / CSS
婚鞋、新娘鞋、礼服鞋、童鞋:Nina Shoes
2019/09/04 全球购物
生物制药自我鉴定
2014/01/25 职场文书
幼儿园教学随笔感言
2014/02/23 职场文书
严以用权专题学习研讨会发言材料
2015/11/09 职场文书
浅谈pytorch中stack和cat的及to_tensor的坑
2021/05/20 Python
Mysql数据库命令大全
2021/05/26 MySQL
Win11筛选键导致键盘失灵怎么解决? Win11关闭筛选键的技巧
2022/04/08 数码科技