JS之闭包与回调
闭包与回调==》JS高级
一、前提
在学好前提下,再来学习闭包与回调
闭包的前提是预编译和作用域
回调的前提是作用域、函数与函数执行
二、闭包
1.什么是闭包?
闭包是面向对象私有化的
一个函数被系统创建出来就是一个闭包
一个函数与环境(作用域)的相互结合
闭包的好处是能给我们带来集成性和封装性
图片如下(示例):
代码如下(示例):
function test(){//是一个闭包
const a = 1;
function fn(){// 是一个闭包 可以调用外部的局部变量
console.log(a)
}
fn()
}
test()
判断这个是不是闭包
function test(){
var b = 222
a(b)
}
function a(b){
console.log(b);
}
test()
// 不是
// 因为 在a()里面只能读取test()里面b的值 ,再添加一个则读取不了,那想读取无数的值呢,这肯定是不行的
// 列:
function test(){
var b = 222
var c = 333
a(b)
}
function a(b){
console.log(b);
console.log(c)
}
test()
出一个简单的小题 加减乘除
// // 第一种方法
// function computer(){
// function add(a,b)
// {
// return a + b
// }
// function sbt(a,b)
// {
// return Math.abs(a - b)
// }
// function mlt(a,b)
// {
// return a * b
// }
// function dvs(a,b)
// {
// return a / b
// }
// // 方法
// // 1.
// // computer.do = function(type,a,b)
// // {
// // switch(type){
// // case 'add':
// // return add(a,b)
// // case 'sbt':
// // return sbt(a,b)
// // case 'mlt':
// // return mlt(a,b)
// // case 'dvs':
// // return dvs(a,b)
// // default:
// // break;
// // }
// // }
// // 2,跟1效果是一样的
// return function(type,a,b)
// {
// switch(type){
// case 'add':
// return add(a,b)
// case 'sbt':
// return sbt(a,b)
// case 'mlt':
// return mlt(a,b)
// case 'dvs':
// return dvs(a,b)
// default:
// break;
// }
// }
// }
// // 1.
// // computer()
// // var ret = computer.do('add', 100,200)
// // console.log(ret)
// // 2,
// // 注意需要大写
// Do = computer()
// const res = Do('add', 100,200)
// console.log(res)
// 第二种写法 比较简便 以对象的形式
// function computer(){
// computer.add = function(a,b)
// {
// return a + b
// }
// computer.sbt = function(a,b)
// {
// return Math.abs(a - b)
// }
// computer.mlt = function(a,b)
// {
// return a * b
// }
// computer.dvs = function(a,b)
// {
// return a / b
// }
// return function(type,a,b){
// return computer[type](a,b)
// }
// }
// Do = computer()
// const res = Do('sbt', 100,200)
// console.log(res)
// 可以再简化一下
function computer(type,c,d){
computer.add = function(a,b)
{
return a + b
}
computer.sbt = function(a,b)
{
return Math.abs(a - b)
}
computer.mlt = function(a,b)
{
return a * b
}
computer.dvs = function(a,b)
{
return a / b
}
return computer[type](c,d)
}
const res = computer('add', 100,200)
console.log(res)
2.关于闭包的相关问题
这个是一个点击事件
代码如下(示例):
问题是缺少闭包,导致最后点击的小li结果都是3(即3 3 3)(他们的总长度是3)(想要的效果是每个小li对应每一个序号)
原因是点击事件并不是作用域,别把绑定事件当成作用域,绑定事件处理函数(这个函数会执行外部的变量)而不是绑定事件直接执行函数
所有在当for都循环完毕,i=3的时候,才能触发绑定事件,那怎么解决呢?
那就是添加立即执行函数(即闭包)
创建了函数时,当i=0时,执行立即执行函数(function(i){}) 此时ii=0 以此类推 i= 1 ii =1; i=2 ii=2
函数里面的括号中的参数是充当临时局部变量(即ii会随着i的变化而变化而不是i循环到最后了ii再执行)
最后的结果是 0 1 2
三、回调
1.什么是回调?
回调的大致意思是:主函数里面的参数是回调函数(即回调函数相当于主函数的参数),主函数执行完毕,再执行回调函数(主函数的事先干完,回头再调用传进来的那个函数。)
这个过程就是回调
代码如下(示例):
//定义主函数,回调函数作为参数
function a(callback){
callback()
console.log('主函数')
}
//定义回调函数 定时器是异步函数
fuction b(){
setTimeout("console.log('我是回调函数')", 3000);//模仿耗时操作
}
//调用主函数,将函数B传进去
a(b)
//输出结果
主函数
我是回调函数
// 主函数
function count(count,callback){
var count1 = count + 1
var count2 = count + 100
callback && callback(count2)
// console.log(count1)
return count1
}
// 这个是回调函数
var count3 = count(1,function(count2){
console.log(count2)
})
console.log(count3)
2.举个栗子
// 加减乘除
function computer(callback){
return function(a,b,type){//这个是一个闭包
let result = null
switch(type){
case '+':
result = a + b
break;
case '-':
result = a - b
break;
case '*':
result = a * b
break;
case '/':
result = a / b
break;
default:
break;
}
callback && callback(a,b,type,result)
}
}
var test = computer(function(a,b,type,result){
console.log(`${a} ${type} ${b} = ${result}`)
})
test(1,2, '+')
test(100,20, '-')
3.验证回调函数
function test(validator){
return function(a,b,type){//这个是一个闭包
var {isError, errorMsg } = validator(a,b)
if(isError){
// throw new Error(error); 这个是创建错误,创造一个错误类型抛出;
throw new Error(errorMsg)
}
switch(type){
case '+':
return a + b
case '-':
return a - b
case '*':
return a * b
case '/':
return a / b
default:
break;
}
}
}
var comp = test(validator)
console.log(comp(100,2,'+'))
function validator(a,b){
if(a > 50 || b > 30){
return {
isError:true,
errorMsg:'a必须小于等于50,并且b小于等于30'
}
}
return{
isError:false,
errorMsg:'ok'
}
}