JS 基础篇(六) 闭包理解与实现

准备知识

词法环境:

词法环境 是定义在词法阶段的作用域,即是 函数声明、变量声明的位置所决定的。
就是 声明函数和变量的当前作用域

全局作用域和局部作用域和块作用域

1.全局作用域:var 关键字 在函数外声明的 所有变量都是 全局作用域的变量,
2.局部作用域:函数内部的变量 属于局部作用域,只能在函数内部访问
3.块作用域:是es6新增的一个概念
  {} 中括号即形成一个块级作用域
  ES6 可以使用 let 关键字或者 const 关键字来实现块级作用域

闭包定义

定义:闭包不单单是一个函数,这个(能够访问其他函数内部变量的)函数 
	连同其对词法环境的引用 捆绑在一起构成了闭包.
	它像是一个桥梁,从函数外部能够访问到函数内部。

code

var a = 1
function fn(){
   var b = 2  //局部作用域
}
console.log(window.a);  //1
console.log(b);  // b is not defined
/*
	由于没有构造闭包,所以b无值
*/

闭包的作用与缺点

作用:
1)能够读取函数函数内部变量
2)让这些变量始终保持在内存中,不会再函数被调用后被自动清除。
3)避免全局变量的污染
缺点:
1)闭包使得函数中的变量保存在内存中,内存消耗很大。所有不能滥用。在IE中导致内存泄漏。
2)闭包会在父函数外部,改变父函数内部变量的值。慎用,不要随便改变
function makeFunc(){
 var name = 'maktub';
  function displayName(){
    alert(name);
  }
  return displayName;
  //形成词法环境
}
var myFunc = makeFunc(); 
//myFunc 引用了函数makeFunc 阻止了name 被回收 而且访问到了 函数内部的变量name
myFunc(); //alert('maktub')

小白:下面这是一个闭包吗?会输出什么?

function f( x ){  
   var a = [];  
   for ( var i = 0; i < x.length; i ++ ){  
   	var temp = x[i];  
    a.push( function(){  
        alert( temp + ' ' + x[i] )  
    });  
   }  
   return a;  
}  
function e(){  
   var a = f( ["a", "b", "c"] );  
   for ( var i = 0; i < a.length; i ++ ){  
       a[i]();  
   }  
}  
e();    // 调用函数e

结果:自行运行
是一个闭包。function里面引用了temp i 变量 ,只是闭包中的变量temp和i 并不是固定的,它会随时根据函数运行环境中的变量的值变化而更新

小白:如果我想要按照 a b c 输出怎么做?

function f( x ){  
     var a = [];  
     for ( var i = 0; i < x.length; i ++ ){  
     	var temp = x[i];  
          a.push( 
			(function(temp, i ){  
		        return function(){
					alert( temp + ' ' + x[i] ) 
				} 
			})(temp,i)
		);  
     }  
     return a;  
 }  
 function e(){  
     var a = f( ["a", "b", "c"] );  
     for ( var i = 0; i < a.length; i ++ ){  
         a[i]();  
     }  
 }  
 e();    // 调用函数e

小白:有更简单的方式吗?
小黑:当然, for循环 声明 i 跟temp 的时候
利用es6中的let也是可以的
code

function f( x ){  
   var a = [];  
   for ( let i = 0; i < x.length; i ++ ){  
   	let temp = x[i];  
    a.push( function(){  
        alert( temp + ' ' + x[i] )  
    });  
   }  
   return a;  
}  
function e(){  
   var a = f( ["a", "b", "c"] );  
   for ( var i = 0; i < a.length; i ++ ){  
       a[i]();  
   }  
}  
e(); 

闭包的应用场景

  • 回调函数 会形成闭包
function makeFunc(fn){
  let num = 1;
  // console.log(num);
  return setTimeout(() => {
    fn(num)
  }, 1000);
}
function callback(number){
  console.log(++number);
}
makeFunc(callback)//2
  • 实际应用场景:实现商品的价格,点击量排序
let lessons = [
  {
    titel:'qqq',
    price:120,
    click:100
  },
  {
    titel:'aaa',
    price:43,
    click:230
  },
  {
    titel:'sss',
    price:12,
    click:80
  },
  {
    titel:'fff',
    price:1,
    click:233
  },
];
let table1 = lessons.sort(function(a,b){
  return a.price > b.price ? 1: -1;
})
console.table(table1)
let table2 = lessons.sort(function(a,b){
  return a.click > b.click ? 1: -1;
})
console.table(table2)

上面这种代码复用率不高,看看闭包的方式

function order(field,type = "asc"){
  return function(a,b){
    if(type == "desc") return a[field] > b[field] ? -1 : 1;
    return a[field] > b[field] ? 1 : -1;
  }
}
let table1 = lessons.sort(order('price'))
console.table(table1);

let table2 = lessons.sort(order('price','desc'))//降序
console.table(table2);

链接

后盾人 ,推荐,适合入门的前端。
综上,另外sort 会在以后的ES6详细整理。
全力以赴奔向你le。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值