准确来说, 闭包是基于正常的垃圾回收处理机制下的. 也就是说, 一般情况一个函数 (函数作用域) 执行完毕, 里面声明的变量会全部释放, 被垃圾回收器回收. 但闭包利用一个技巧, 让作用域里面的变量, 在函数执行完之后依旧保存没有被垃圾回收处理掉.
闭包
定义
MDN 定义
javascriptkit
词法作用域
作用域链
函数在执行的过程中, 先从自己内部找变量如果找不到, 再从创建当前函数所在的作用域 (词法作用域) 去找, 以 此往上注意找的是变量的当前的状态
作用域链的博客
函数连同它作用域链上的要找的这个变量, 共同构成闭包
一般情况下使用闭包主要是为了
封装数据
暂存数据
一个典型的闭包案例
- 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)
- // 欢迎加入全栈开发交流群一起学习交流: 864305860
- 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
- var Car = (function(){
- var speed = 0;
- function set(s){
- speed = s
- }
- function get(){
- return speed
- }// 欢迎加入全栈开发交流裙一起学习交流: 864305860
- 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() //30
- // 欢迎加入全栈开发交流群一起学习交流: 864305860
- for(var i=0; i<5; i++){
- setTimeout(function(){
- console.log('delayer:' + i )
- }, 0)
- }
- 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'))
- console.log( sum(1)(2) ) // 3
- console.log( sum(5)(-1) ) // 4
- // 欢迎加入全栈开发交流裙一起学习交流: 864305860
来源: http://www.qdfuns.com/article/51117/8644f5786142a200d7d9f61ae4285bdc.html