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 相关文章推荐
cnblogs中在闪存中屏蔽某人的实现代码
Nov 14 Javascript
在javascript中如何得到中英文混合字符串的长度
Jan 17 Javascript
解决checkbox的attr(checked)一直为undefined问题
Jun 16 Javascript
使用JS实现jQuery的addClass, removeClass, hasClass函数功能
Oct 31 Javascript
jquery实现简易的移动端验证表单
Nov 08 Javascript
js实现的下拉框二级联动效果
Apr 30 Javascript
JavaScript中数组slice和splice的对比小结
Sep 22 Javascript
微信小程序 教程之WXML
Oct 18 Javascript
jQuery实现鼠标点击处心形漂浮的炫酷效果示例
Apr 12 jQuery
解决node-sass偶尔安装失败的方法小结
Dec 05 Javascript
微信小程序自定义组件实现环形进度条
Nov 17 Javascript
js实现贪吃蛇小游戏
Oct 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 面试碰到过的问题 在此做下记录
2011/06/09 PHP
PHP批量生成静态HTML的简单原理和方法
2014/04/20 PHP
Zend Framework入门知识点小结
2016/03/19 PHP
Netbeans 8.2将支持PHP7 更精彩
2016/06/13 PHP
php版微信开发之接收消息,自动判断及回复相应消息的方法
2016/09/23 PHP
php 实现一个字符串加密解密的函数实例代码
2016/11/01 PHP
PHP手机号中间四位用星号*代替显示的实例
2017/06/02 PHP
javascript 动态添加事件代码
2008/11/30 Javascript
使用js获取QueryString的方法小结
2010/02/28 Javascript
JavaScript中Date对象的常用方法示例
2015/10/24 Javascript
jQuery解析json格式数据简单实例
2016/01/22 Javascript
JavaScript中获取HTML元素值的三种方法
2016/06/20 Javascript
详解React开发中使用require.ensure()按需加载ES6组件
2017/05/12 Javascript
ionic环境配置及问题详解
2017/06/27 Javascript
javascript兼容性(实例讲解)
2017/08/15 Javascript
mescroll.js上拉加载下拉刷新组件使用详解
2017/11/13 Javascript
Vue.set()实现数据动态响应的方法
2018/02/07 Javascript
angularjs 缓存的使用详解
2018/03/19 Javascript
浅谈super-vuex使用体验
2018/06/25 Javascript
vue-router实现编程式导航的代码实例
2019/01/19 Javascript
浅谈JS中几种轻松处理'this'指向方式
2019/09/16 Javascript
Node.js API详解之 assert模块用法实例分析
2020/05/26 Javascript
python读写ini文件示例(python读写文件)
2014/03/25 Python
pygame 精灵的行走及二段跳的实现方法(必看篇)
2017/07/10 Python
浅谈Python 多进程默认不能共享全局变量的问题
2019/01/11 Python
对python:threading.Thread类的使用方法详解
2019/01/31 Python
Python绘图Matplotlib之坐标轴及刻度总结
2019/06/28 Python
python函数声明和调用定义及原理详解
2019/12/02 Python
Python实现手机号自动判断男女性别(实例解析)
2019/12/22 Python
Python龙贝格法求积分实例
2020/02/29 Python
html5 canvas实现给图片添加平铺水印
2019/08/20 HTML / CSS
苹果Mac升级:MacSales.com
2017/11/20 全球购物
2014年小学数学工作总结
2014/12/12 职场文书
2015新年联欢晚会开场白
2014/12/14 职场文书
运动会开幕式通讯稿
2015/07/18 职场文书
TensorFlow的自动求导原理分析
2021/05/26 Python