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中几种常见排序算法小结
Feb 22 Javascript
js 中{},[]中括号,大括号使用详解
May 12 Javascript
Jquery选中或取消radio示例
Sep 29 Javascript
js中string转int把String类型转化成int类型
Aug 13 Javascript
JS+CSS实现简单滑动门(滑动菜单)效果
Sep 19 Javascript
JS 动态加载js文件和css文件 同步/异步的两种简单方式
Sep 23 Javascript
JavaScript中boolean类型之三种情景实例代码
Nov 21 Javascript
浅谈jquery采用attr修改form表单enctype不起作用的问题
Nov 25 Javascript
教你快速搭建Node.Js服务器的方法教程
Mar 30 Javascript
js字符限制(字符截取) 一个中文汉字算两个字符
Sep 12 Javascript
灵活使用console让js调试更简单的方法步骤
Apr 23 Javascript
原生js实现弹幕效果
Nov 29 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 Xdebug 本地与远程调试(小结)
2019/04/23 PHP
很可爱的输入框
2008/08/03 Javascript
jquery1.83 之前所有与异步列队相关的模块详细介绍
2012/11/13 Javascript
用js实现控件的隐藏及style.visibility的使用
2013/06/14 Javascript
js计算两个时间之间天数差的实例代码
2013/11/19 Javascript
5个JavaScript经典面试题
2014/10/13 Javascript
js在指定位置增加节点函数insertBefore()用法实例
2015/01/12 Javascript
NodeJS Web应用监听sock文件实例
2015/02/18 NodeJs
JS模仿编辑器实时改变文本框宽度和高度大小的方法
2015/08/17 Javascript
深入理解JS函数的参数(arguments)的使用
2016/05/28 Javascript
javascript实现将数字转成千分位的方法小结【5种方式】
2016/12/11 Javascript
fullPage.js和CSS3实现全屏滚动效果
2017/05/05 Javascript
vue.js2.0点击获取自己的属性和jquery方法
2018/02/23 jQuery
关于Vue项目跨平台运行问题的解决方法
2018/09/18 Javascript
js实现导航跟随效果
2018/11/17 Javascript
JavaScript创建对象的四种常用模式实例分析
2019/01/11 Javascript
利用Node.js如何实现文件循环覆写
2019/04/05 Javascript
Python中使用glob和rmtree删除目录子目录及所有文件的例子
2014/11/21 Python
MySQL最常见的操作语句小结
2015/05/07 Python
在Linux命令行终端中使用python的简单方法(推荐)
2017/01/23 Python
python对视频画框标记后保存的方法
2018/12/07 Python
python引用(import)某个模块提示没找到对应模块的解决方法
2019/01/19 Python
详解Python中正则匹配TAB及空格的小技巧
2019/07/26 Python
Python 使用元类type创建类对象常见应用详解
2019/10/17 Python
Python中实现输入一个整数的案例
2020/05/03 Python
Python 分布式缓存之Reids数据类型操作详解
2020/06/24 Python
Python持续监听文件变化代码实例
2020/07/22 Python
分享CSS3中必须要知道的10个顶级命令
2012/04/26 HTML / CSS
意大利在线高尔夫商店:Online Golf
2021/03/09 全球购物
考试没考好检讨书
2014/01/31 职场文书
创建省级文明单位实施方案
2014/02/27 职场文书
学前班学生评语
2014/12/29 职场文书
2015年财务经理工作总结
2015/05/13 职场文书
大学副班长竞选稿
2015/11/21 职场文书
2019年感恩励志演讲稿(收藏备用)
2019/09/11 职场文书
Python if else条件语句形式详解
2022/03/24 Python