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 相关文章推荐
Javascript中的var_dump函数实现代码
Sep 07 Javascript
利用CSS、JavaScript及Ajax实现高效的图片预加载
Oct 16 Javascript
JS去除空格和换行的正则表达式(推荐)
Jun 14 Javascript
js实现动态显示时间效果
Mar 06 Javascript
使用requirejs模块化开发多页面一个入口js的使用方式
Jun 14 Javascript
关于 angularJS的一些用法
Nov 29 Javascript
使用Bootstrap4 + Vue2实现分页查询的示例代码
Dec 21 Javascript
基于vue-simplemde实现图片拖拽、粘贴功能
Apr 12 Javascript
解决Layui数据表格中checkbox位置不居中的方法
Aug 15 Javascript
JS实现查找数组中对象的属性值是否存在示例
May 24 Javascript
el-table树形表格表单验证(列表生成序号)
May 31 Javascript
javascript实现点击按钮切换轮播图功能
Sep 23 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
《斗罗大陆》六翼天使武魂最强,为什么老千家不是上三宗?
2020/03/02 国漫
探讨file_get_contents与curl效率及稳定性的分析
2013/06/06 PHP
Mac OS下配置PHP+MySql环境
2015/02/25 PHP
WordPress中登陆后关闭登陆页面及设置用户不可见栏目
2015/12/31 PHP
php+ajax实现带进度条的上传图片功能【附demo源码下载】
2016/09/14 PHP
thinkPHP5.0框架验证码调用及点击图片刷新简单实现方法
2018/09/07 PHP
Laravel 自动转换长整型雪花 ID 为字符串的实现
2020/10/27 PHP
JS调用CS里的带参方法实例
2013/08/01 Javascript
JavaScript代码判断点击第几个按钮
2015/12/13 Javascript
判断js的Array和Object的实现方法
2016/08/29 Javascript
微信小程序 框架详解及实例应用
2016/09/26 Javascript
JS常见创建类的方法小结【工厂方式,构造器方式,原型方式,联合方式等】
2017/04/01 Javascript
基于bootstrap写的一点localStorage本地储存
2017/11/21 Javascript
js生成word中图片处理方法
2018/01/06 Javascript
vue中手机号,邮箱正则验证以及60s发送验证码的实例
2018/03/16 Javascript
Vue.js 中取得后台原生HTML字符串 原样显示问题的解决方法
2018/06/10 Javascript
Python实现大文件排序的方法
2015/07/10 Python
Python之re操作方法(详解)
2017/06/14 Python
Python自定义线程类简单示例
2018/03/23 Python
Python3 jupyter notebook 服务器搭建过程
2018/11/30 Python
Python 中包/模块的 `import` 操作代码
2019/04/22 Python
Python流行ORM框架sqlalchemy安装与使用教程
2019/06/04 Python
python 实现一个反向单位矩阵示例
2019/11/29 Python
python实现三种随机请求头方式
2021/01/05 Python
Algenist奥杰尼官网:微藻抗衰老护肤品牌
2017/07/15 全球购物
俄罗斯天然和有机产品、健康生活网上商店:Fitomarket.ru
2020/10/09 全球购物
C#笔试题集合
2013/06/21 面试题
同学聚会策划方案
2014/06/06 职场文书
幼儿教师师德师风自我剖析材料
2014/09/29 职场文书
植树节新闻稿
2015/07/17 职场文书
保护环境建议书作文500字
2015/09/14 职场文书
《自己的花是让别人看的》教学反思
2016/02/19 职场文书
2016年感恩节活动总结大全
2016/04/01 职场文书
Python 高级库15 个让新手爱不释手(推荐)
2021/05/15 Python
MongoDB日志切割的三种方式总结
2021/09/15 MongoDB
Pandas搭配lambda组合使用详解
2022/01/22 Python