js中的闭包实例展示


Posted in Javascript onNovember 01, 2018

前言

准确来说,闭包是基于正常的垃圾回收处理机制下的。也就是说,一般情况一个函数(函数作用域)执行完毕,里面声明的变量会全部释放,被垃圾回收器回收。但闭包利用一个技巧,让作用域里面的变量,在函数执行完之后依旧保存没有被垃圾回收处理掉。

闭包

定义

MDN定义

javascriptkit

词法作用域

闭包的三大特点为:

1、函数嵌套函数

2、内部函数可以访问外部函数的变量

3、参数和变量不会被回收。

作用域链
函数在执行的过程中,先从自己内部找变量如果找不到,再从创建当前函数所在的作用域(词法作用域)去找, 以 此往上注意找的是变量的当前的状态

作用域链的博客

函数连同它作用域链上的要找的这个变量,共同构成闭包

一般情况下使用闭包主要是为了

  • 封装数据
  • 暂存数据

一个典型的闭包案例

function car(){
 var speed = 0
 function fn(){
 speed++
 console.log(speed)
 }
 return fn
}
var speedUp = car()
speedUp() //1
speedUp() //2

当函数内部没有执行以下的代码时

function fn(){
 speed++
 console.log(speed)
 }
return fn

在代码执行完成后,函数内部的局部变量speed就会被销毁,由于全局标量speedUp一直存在(除非关闭当前页面,否则全局变量一直存在),那么函数内部的作用域就没有办法被销毁,里面有东西一直被使用,这点与浏览器的垃圾回收机制相仿,当我们执行speedUp(),他会在函数的词法作用域下去寻找,函数里面又返回了一个fn,因而形成闭包,简单的理解为

var speed = 0
function fn(){
 speed++
 console.log(speed)
}

这一段代码形成一个闭包,如果不return fn,那函数内部的局部变量就会被销毁。

我们可以看看上述代码利用立即执行语句和立即执行函数可以怎么演变:

function car(){
 var speed = 0
 function fn(){
 speed++
 console.log(speed)
 }
 return fn
}
var speedUp = car()
//1
function car(){
 var speed = 0
 return function (){
 speed++
 console.log(speed)
 }
}
var speedUp = car()
//2
function car(speed){
 return function (){
 speed++
 console.log(speed)
 }
}
var speedUp = car(3)
//3
function car(){
 var speed = arguments[0]
 return function (){
 speed++
 console.log(speed)
 }
}
var speedUp = car()
//4
function car(){
 var speed = 0
 return function (){
 speed++
 console.log(speed)
 }
}
//5 car可以不写,则为匿名函数 
var speedUp = (function car(speed){
 return function (){
 speed++
 console.log(speed)
 }
}
)(3)

闭包的相关案例

如下代码输出多少?如果想输出3,那如何改造代码?

var fnArr = [];
for (var i = 0; i < 10; i ++) {
 fnArr[i] = function(){
 return i
 };
}
console.log( fnArr[3]() ) // 10

同等演变

假设只有两层循环:

var fnArr = []
for (var i = 0; i < 2; i ++) {
 fnArr[i] = (function(j){
 return function(){
 return j
 } 
 })(i)
}
fnArr[3]()
//1
var fnArr = [] 
fnArr[0] = (function(j){
 return function(){
 return j
 } 
 })(0)
}
fnArr[1] = (function(j){
 return function(){
 return j
 } 
 })(1)
}
fnArr[3]()
//2
var a = (function(j){
 return function(){
 return j
 } 
 })(0)
}
var b = (function(j){
 return function(){
 return j
 } 
 })(1)
}
b()
//3
var a = (function(j){
 return function(){
 return j
 } 
 })(0)
}
function fn2(j){
 return function(){
 return j
 }
}
var b = fn2(1)
//4
var a = (function(j){
 return function(){
 return j
 } 
 })(0)
}
function fn2(j){
 return function(){
 return j
 }
 return f
}
var b = fn2(1)
//5
var a = (function(j){
 return function(){
 return j
 } 
 })(0)
}
function fn2(j){
 var j = arguments[0]
 function f(){
 return j
 }
 return f
}
var b = fn2(1)

改造后(立即执行语句,演变过程)

var fnArr = []
for (var i = 0; i < 10; i ++) {
 fnArr[i] = (function(j){
 return function(){
 return j
 } 
 })(i)
}
console.log( fnArr[3]() ) // 3
var fnArr = []
for (var i = 0; i < 10; i ++) {
 (function(i){
 fnArr[i] = function(){
 return i
 } 
 })(i)
}
console.log( fnArr[3]() ) // 3
var fnArr = []
for (let i = 0; i < 10; i ++) {
 fnArr[i] = function(){
 return i
 } 
}
console.log( fnArr[3]() ) // 3

封装一个 Car 对象

var Car = (function(){
 var speed = 0;
 function set(s){
 speed = s
 }
 function get(){
 return speed
 }
 function speedUp(){
 speed++
 }
 function speedDown(){
 speed--
 }
 return {
 setSpeed: setSpeed,
 get: get,
 speedUp: speedUp,
 speedDown: speedDown
 }
})()
Car.set(30)
Car.get() //30
Car.speedUp()
Car.get() //31
Car.speedDown()
Car.get() //3

如下代码输出多少?如何连续输出 0,1,2,3,4

for(var i=0; i<5; i++){
 setTimeout(function(){
 console.log('delayer:' + i )
 }, 0)
}

输出结果为:delayer:5(连续输出5个),执行setTimeout时,代码会挂到任务队列中区,待i遍历完成之后执行,而此时i = 5,所以输出delayer:5(连续输出5个)

修改后

for(var i=0; i<5; i++){
 (function(j){
 setTimeout(function(){
 console.log('delayer:' + j )
 }, 0)//1000-1000*j 
 })(i)
}

或者

for(var i=0; i<5; i++){
 setTimeout((function(j){
 return function(){
 console.log('delayer:' + j )
 }
 }(i)), 0) 
}

如下代码输出多少?

function makeCounter() {
 var count = 0
 return function() {
 return count++
 };
}
var counter = makeCounter()
var counter2 = makeCounter();
console.log( counter() ) // 0
console.log( counter() ) // 1
console.log( counter2() ) // 0
console.log( counter2() ) // 1

补全代码,实现数组按姓名、年纪、任意字段排序

var users = [
 { name: "John", age: 20, company: "Baidu" },
 { name: "Pete", age: 18, company: "Alibaba" },
 { name: "Ann", age: 19, company: "Tecent" }
]
users.sort(byName) 
users.sort(byAge)
users.sort(byField('company'))

解答

function byName(user1, user2){
 return user1.name > user2.name
}
function byAge (user1, user2){
 return user1.age > user2.age
}
function byFeild(field){
 return function(user1, user2){
 return user1[field] > user2[field]
 }
}
users.sort(byField('company'))

写一个 sum 函数,实现如下调用方式

console.log( sum(1)(2) ) // 3
console.log( sum(5)(-1) ) // 4

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
JS解析XML的实现代码
Nov 12 Javascript
jquery 学习笔记一
Apr 07 Javascript
Jquery判断IE6等浏览器的代码
Apr 05 Javascript
优化RequireJS项目的相关技巧总结
Jul 01 Javascript
关于JS中prototype的理解
Sep 07 Javascript
JS模拟酷狗音乐播放器收缩折叠关闭效果代码
Oct 29 Javascript
javascript禁止超链接跳转的方法
Feb 02 Javascript
jQuery+正则+文本框只能输入数字的实现方法
Oct 07 Javascript
最原始的jQuery注册验证方式
Oct 11 Javascript
解决Extjs下拉框不显示的问题
Jun 21 Javascript
浅谈VUE中演示v-for为什么要加key
Jan 16 Javascript
使用typescript改造koa开发框架的实现
Feb 04 Javascript
微信小程序实现登录遮罩效果
Nov 01 #Javascript
在vue里使用codemirror遇到的问题
Nov 01 #Javascript
vue中使用codemirror的实例详解
Nov 01 #Javascript
vue-lazyload使用总结(推荐)
Nov 01 #Javascript
vue 中基于html5 drag drap的拖放效果案例分析
Nov 01 #Javascript
Vue列表渲染的示例代码
Nov 01 #Javascript
socket io与vue-cli的结合使用的示例代码
Nov 01 #Javascript
You might like
php官方微信接口大全(微信支付、微信红包、微信摇一摇、微信小店)
2015/12/21 PHP
分享php邮件管理器源码
2016/01/06 PHP
php好代码风格的阶段性总结
2016/06/25 PHP
利用XMLHTTP传递参数在另一页面执行并刷新本页
2006/10/26 Javascript
CCPry JS类库 代码
2009/10/30 Javascript
基于Jquery的仿Windows Aero弹出窗(漂亮的关闭按钮)
2010/09/28 Javascript
从js向Action传中文参数出现乱码问题的解决方法
2013/12/29 Javascript
利用javascript判断文件是否存在
2013/12/31 Javascript
jquery插件lazyload.js延迟加载图片的使用方法
2014/02/19 Javascript
JQuery中层次选择器用法实例详解
2015/05/18 Javascript
关于获取DIV内部内容报错的原因分析及解决办法
2016/01/29 Javascript
谷歌showModalDialog()方法不兼容出现对话窗口的解决办法
2016/02/15 Javascript
JavaScript中三个等号和两个等号的区别(== 和 ===)浅析
2016/09/22 Javascript
解析javascript图片懒加载与预加载的分析总结
2016/10/27 Javascript
Vue-router路由判断页面未登录跳转到登录页面的实例
2017/10/26 Javascript
js 将canvas生成图片保存,或直接保存一张图片的实现方法
2018/01/02 Javascript
vue中vee validate表单校验的几种基本使用
2018/06/25 Javascript
node.js实现上传文件功能
2019/07/15 Javascript
详解vue3.0 diff算法的使用(超详细)
2020/07/01 Javascript
[02:43]DOTA2英雄基础教程 德鲁伊
2014/01/13 DOTA
python PIL模块与随机生成中文验证码
2016/02/27 Python
Python利用前序和中序遍历结果重建二叉树的方法
2016/04/27 Python
学习python可以干什么
2019/02/26 Python
Python实现的爬取百度贴吧图片功能完整示例
2019/05/10 Python
python批量爬取下载抖音视频
2019/06/17 Python
pytorch多GPU并行运算的实现
2019/09/27 Python
python爬虫爬取监控教务系统的思路详解
2020/01/08 Python
Python使用扩展库pywin32实现批量文档打印实例
2020/04/09 Python
Python下载的11种姿势(小结)
2020/11/18 Python
HTML5无刷新改变当前url的代码
2017/03/15 HTML / CSS
学校运动会霸气口号
2014/06/07 职场文书
羽毛球社团活动总结
2014/06/27 职场文书
小学毕业感言200字
2015/07/30 职场文书
python实现批量提取指定文件夹下同类型文件
2021/04/05 Python
纯CSS实现酷炫的霓虹灯效果
2021/04/13 HTML / CSS
MySQL 十大常用字符串函数详解
2021/06/30 MySQL