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 相关文章推荐
JQuery EasyUI 对话框的使用方法
Oct 24 Javascript
鼠标移到导航当前位置的LI变色处于选中状态
Aug 23 Javascript
JavaScript移除数组内重复元素的方法
Mar 18 Javascript
jQuery获取页面及个元素高度、宽度的总结——超实用
Jul 28 Javascript
深入浅析JavaScript中数据共享和数据传递
Apr 25 Javascript
Bootstrap学习笔记之js组件(4)
Jun 12 Javascript
jQuery模拟爆炸倒计时功能实例代码
Aug 21 jQuery
react-navigation 如何判断用户是否登录跳转到登录页的方法
Dec 01 Javascript
Vue兼容ie9的问题全面解决方案
Jun 19 Javascript
小程序指纹验证的实现代码
Dec 04 Javascript
新手如何快速理解js异步编程
Jun 24 Javascript
js实现贪吃蛇小游戏(加墙)
Jul 31 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
全国FM电台频率大全 - 31 新疆维吾尔族自治区
2020/03/11 无线电
CentOS6.5 编译安装lnmp环境
2014/12/21 PHP
给ECShop添加最新评论
2015/01/07 PHP
Symfony生成二维码的方法
2016/02/04 PHP
ThinkPHP删除栏目(实现批量删除栏目)
2017/06/21 PHP
PHP通过文件保存和更新信息的方法分析
2019/09/12 PHP
Mootools 图片展示插件(lightbox,ImageMenu)收集集合
2010/05/21 Javascript
jQuery实现强制cookie过期方法汇总
2015/05/22 Javascript
JS利用cookie记忆当前位置的防刷新导航效果
2015/10/15 Javascript
Angular1.x自定义指令实例详解
2017/03/01 Javascript
判断颜色是否合法的正则表达式(详解)
2017/05/03 Javascript
引入JavaScript时alert弹出框显示中文乱码问题
2017/09/16 Javascript
jquery在启动页面时,自动加载数据的实例
2018/01/22 jQuery
Vue实现搜索 和新闻列表功能简单范例
2018/03/16 Javascript
利用weixin-java-miniapp生成小程序码并直接返回图片文件流的方法
2019/03/29 Javascript
利用Node.js如何实现文件循环覆写
2019/04/05 Javascript
微信小程序12行js代码自己写个滑块功能(推荐)
2020/07/15 Javascript
javascript解析json格式的数据方法详解
2020/08/07 Javascript
jQuery冲突问题解决方法
2021/01/19 jQuery
Python实现字典的key和values的交换
2015/08/04 Python
python 3.0 模拟用户登录功能并实现三次错误锁定
2017/11/01 Python
Python lambda函数基本用法实例分析
2018/03/16 Python
解决Ubuntu pip 安装 mysql-python包出错的问题
2018/06/11 Python
python腾讯语音合成实现过程解析
2019/08/01 Python
十月份红领巾广播稿
2014/01/22 职场文书
人力资源部经理助理岗位职责
2014/03/04 职场文书
空中乘务员岗位职责
2014/03/08 职场文书
经济管理专业求职信
2014/06/09 职场文书
社区活动总结
2015/02/04 职场文书
单身证明格式样本
2015/06/15 职场文书
干部理论学习心得体会
2016/01/21 职场文书
大学生社区义工服务心得体会
2016/01/22 职场文书
2016中秋节广告语
2016/01/28 职场文书
Python如何把不同类型数据的json序列化
2021/04/30 Python
OpenCV实现普通阈值
2021/11/17 Java/Android
Sql Server 行数据的某列值想作为字段列显示的方法
2022/04/20 SQL Server