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对象学习经验整理
Oct 12 Javascript
js抽奖实现随机抽奖代码效果
Dec 02 Javascript
jquery操作cookie插件分享
Jan 14 Javascript
JavaScript获取table中某一列的值的方法
May 06 Javascript
基于gulp合并压缩Seajs模块的方式说明
Jun 14 Javascript
JS基于面向对象实现的拖拽功能示例
Dec 20 Javascript
解决vue2.0路由跳转未匹配相应用路由避免出现空白页面的问题
Aug 24 Javascript
Vue.js 中的 v-cloak 指令及使用详解
Nov 19 Javascript
BootStrap模态框闪退问题实例代码详解
Dec 10 Javascript
使用vue-router切换页面时,获取上一页url以及当前页面url的方法
May 06 Javascript
2019最新21个MySQL高频面试题介绍
Feb 06 Javascript
vue 使用v-for进行循环的实例代码详解
Feb 19 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
zf框架db类的分页示例分享
2014/03/14 PHP
Fatal error: session_start(): Failed to initialize storage module: files问题解决方法
2014/05/04 PHP
ThinkPHP快速入门实例教程之数据分页
2014/07/01 PHP
PHP SESSION的增加、删除、修改、查看操作
2015/03/20 PHP
PHP加密解密字符串汇总
2015/04/26 PHP
PHP中函数gzuncompress无法使用的解决方法
2017/03/02 PHP
基于Laravel实现的用户动态模块开发
2017/09/21 PHP
JavaScript 权威指南(第四版) 读书笔记
2009/08/11 Javascript
Tab切换组件(选项卡功能)实例代码
2013/11/21 Javascript
js生成动态表格并为每个单元格添加单击事件的方法
2014/04/14 Javascript
JS中getYear()和getFullYear()区别分析
2014/07/04 Javascript
js实现遮罩层划出效果是生成div而不是显示
2014/07/29 Javascript
简单方法判断JavaScript对象为null或者属性为空
2014/09/26 Javascript
详解JS函数重载
2014/12/04 Javascript
Jquery实现遮罩层的方法
2015/06/08 Javascript
jQuery实现自动调整字体大小的方法
2015/06/15 Javascript
easyui messager alert 三秒后自动关闭提示的实例
2016/11/07 Javascript
jQuery 实现左右两侧菜单添加、移除功能
2018/01/02 jQuery
使用selenium抓取淘宝的商品信息实例
2018/02/06 Javascript
Vue的路由动态重定向和导航守卫实例
2018/03/17 Javascript
ES6学习笔记之let与const用法实例分析
2020/01/22 Javascript
JS+HTML5本地存储Localstorage实现注册登录及验证功能示例
2020/02/10 Javascript
JS 获取文件后缀,判断文件类型(比如是否为图片格式)
2020/05/09 Javascript
python+matplotlib实现礼盒柱状图实例代码
2018/01/16 Python
pytorch索引查找 index_select的例子
2019/08/18 Python
Python面向对象之私有属性和私有方法应用案例分析
2019/12/31 Python
新加坡时尚网上购物:Zalora新加坡
2016/07/26 全球购物
Book Depository澳大利亚:世界领先的专业在线书店之一
2018/12/27 全球购物
高校毕业生自我鉴定
2013/10/27 职场文书
大学生简历的个人自我评价
2013/12/04 职场文书
公司外出活动方案
2014/08/14 职场文书
超市仓管员岗位职责范本
2014/09/18 职场文书
工作违纪检讨书范文
2015/01/26 职场文书
tensorflow学习笔记之tfrecord文件的生成与读取
2021/03/31 Python
解决Django transaction进行事务管理踩过的坑
2021/04/24 Python
Python pandas之求和运算和非空值个数统计
2021/08/07 Python