概述:闭包就是函数内部返回一个函数,内部函数有外部函数的引用,这个结果称为闭包.
函数的生命周期
functon fn(){
var i = 0
i++
return i
}
console.log(fn()) //1 第一个i变量
console.log(fn()) //1 第二个i变量
函数在预编译阶段
函数执行阶段
function fn(){
var i =0
i++
return{
i
}
}
var obj =fn()
console.log(obj.i)
通过上述代码 我们可以保持对应于i的引用,保证i不会回收,以返回一个引用数据类型来保持对应i 的引用. 那么对应函数也是一个引用数据类型,那可以通过返回函数的形式来保证i的唯一性
function fn(){
var i = 0
return function(){
i++
console.log(i)
}
}
var f =fn()
f()//1
f()//2
f()//3
而上面这种保证i不被回收的机制就叫做闭包(返回一个引用数据类型 这个里面保证对i的引用 从而不被回收)
闭包的优势劣势
优势
闭包的应用
防抖(在规定时间内只执行一次 执行最后一次)
示例(等电梯)
//第一个参数是做的操作 第二个是等待时间
function debounce(timer,delay){
var timer =null
return function(){
clearTimeout(timer)
timer =setTimeout(fn,delay)
}
}
节流 (在规定时间内执行第一次 减少执行次数)
示例(红绿灯)
//操作 执行一次的时长
function throttle(fn,delay){
var timer = null
return function(){
//判断上一次是否走完
if(timer) return
//上一次走完了开始下一次
timer = setTimeout(()=>{
fn()
//走完了要将节流阀设置为false
timer = null
},delay)
}
}
防抖和节流的区别
函数柯里化 (将多个参数的函数拆分为多个单参数的函数 可以自由的组合)
示例
function sum(a,b){
return a+b
}
console.log(sum(1,2)) //结果3
简单的函数柯里化
function sum(a) {
return function (b) {
return function (c) {
return a + b + c
}
}
}
console.log(sum(1)(2)); //结果是函数
console.log(sum(1)(2)(3));//结果是6
核心就是参数没有够返回对应的函数,参数够了返回结果
高阶函数柯里化
//传递一个函数 (参数没到返回函数 参数到了返回结果)
function currying(fn) {
//获取currying传递的参数
let args = Array.prototype.slice.call(arguments,1)
return function () {
//将对应的函数的参数和curry传递参数做连接
let arg = Array.from(arguments).concat(args)
//判断参数个数是否一样
if(arg.length < fn.length){
//参数没到返回函数
return currying.call(this,fn,...arg)
}else{
//参数到了 调用方法返回结果
return fn.apply(this,arg)
}
}
}
调用
function sum(a,b,c){
return a+b+c
}
console.log(`sum(1,2,3)`, sum(1,2,3));
let fn = currying(sum)
console.log(`fn(2)`, fn(2));//函数
console.log(`fn(2)(3)`, fn(2)(3));//函数
console.log(`fn(2)(3)(1)`, fn(2)(3)(1));//6
console.log(` fn()()()(2)()()(3)()()()(1)`, fn()()()(2)()()(3)()()()(10));//15
概述:promise是es6新增的一个类,这个类翻译为承诺,它有三种状态 等待状态 成功状态 拒绝状态 .它被设计为异步的,它里面的内容是异步的(方法为异步)
promise的三种状态
构建promise对象
new promise (成功的函数,失败的函数)=>{
代码块
}
//里面传递的参数是一个函数
//这个传递的函数里面有俩个参数 这个俩个参数也是一个函数
//这个函数里面的第一个参数为成功的函数 resolve 第二个参数为失败的函数 reject (这个俩个函数
都是异步的)
var promise = new Promise((revlose,reject)=>{
console.log('我是默认的'); //pending 结果是undefined
// revlose('我是成功了') //状态fulfilled 结果是我是成功了
// reject('我被拒绝了')//状态是rejected 结果是我被拒绝了
// throw new Error('我是个错误') //状态是rejected 结果是我是个错误
})
console.log(promise);
promise的方法
原型方法
//第一个为成功的函数 第二个为失败的函数
var promise = new Promise((resolve, reject) => {
resolve('我成功了')
// console.log('哥是默认的');
// reject('我失败了')
// throw new Error('我是个错误')
})
promise.then((a) => {
console.log('嗯', a); //结果为成功的 嗯 我
}, (b) => {
console.log('哦', b); //结果为失败的
})
then的注意事项
var promise = new Promise((resolve,reject)=>{
//成功的函数调用 传递对应的参数
resolve('成功')
})
promise.then((res)=>{
console.log(`第一次then`, res);
return 'hello'
}).then((res)=>{
console.log(`第二次then`, res);
return 'world'
}).then((res)=>{
console.log(`第三次then`, res);
return 'abc'
}).then() //值穿透 当你的then没有处理它会给到下一个处理
.
then((res)=>{
console.log(`第n次then`, res);
})
注意事项
catch 执行失败
var promise = new Promise((resolve, reject) => {
reject('失败')
// throw new Error('失败了')
})
//.catch默认请求下只执行第一个 如果需要走下面的 那么需要你报错
promise.catch(a => {
console.log('俺不会', a);
throw new Error('报错了')
}).catch(a => {
console.log('俺会了', a);
throw new Error('给下个')
}).catch(a => {
console.log('哦', a);
throw new Error('不要')
}).catch()//值穿透哦
.catch(a => {
console.log('结束了不要往下给了', a);
})
注意事项
finally 执行完成调用的
//promise promise只能满足于一种状态 进入到成功它就成功了 进入失败就失败了
var success = new Promise((resolve,reject)=>{
//成功的函数调用 传递对应的参数
resolve('成功')
reject('失败')
// throw new Error('失败了')
})
//成功的回调 俩个参数 成功的函数 失败的函数
success.then((res)=>{//res会接收resolve传递的参数
console.log(`res`, res);
},(error)=>{//error 接收reject传递的参数
console.log(`error`, error);
})
//失败的回调 参数1个 传递为一个函数 这个函数可以接收rejected传递的参数
success.catch((error)=>{
console.log(`rejected`, error);
})
//完成就能调用的函数 (成功 失败)
success.finally(()=>{
console.log(`完成了`);
})
静态方法
promise的三种状态图
回调地狱
概述:回调函数的无限嵌套导致当前代码失去了对应的维护价值及对应的可读性。
示例
//传入一个函数作为回调函数 在对应代码执行完成调用
function fn(fn) {
setTimeout(function () {
console.log('10');
//走完了以后回调函数执行
fn()
}, 1000)
}
fn(() => {
console.log(1);
})
//多个回调函数嵌套 回调地狱 (回调函数的无限嵌套 代码的可读性 可维护性 已经失去了)
fn(() => {
console.log(1);
fn(() => {
console.log(2);
fn(() => {
console.log(3);
fn(() => {
console.log(4);
fn(() => {
console.log(5);
fn(() => {
console.log(6);
....
})
})
})
})
})
})
promise来解决回调地狱(链式调用)
在.then里面返回一个新的promise对象 在对应的异步代码执行完后调用resolve
//利用promise来解决回调地狱的问题
new Promise((resolve, reject) => {
setTimeout(() => {
console.log(1);
resolve()
});
}).then(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(2);
resolve()
});
})
}).then(()=>{
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(3);
resolve()
});
})
}).then(()=>{
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(4);
resolve()
});
})
}).then(()=>{
console.log(5);
})
概述 async和await是对应的两个连用的关键词,async是修饰函数的,await是修饰promise的.await只能在async内使用,async修饰的函数返回一个promise对象,await修饰的promise对象会占用当前线程 知道对应的promise执行完成才会释放.
async function fn() {
await new Promise((resolve,reject)=>{ //如果没有放行后面的不会执行
setTimeout(() => {
console.log('hello');
resolve()
})
})
console.log('world');
}
//async修饰完函数执行会返回一个promise对象
console.log(fn());
//async修饰的函数返回的promise对象
//里面的报错 会使当前的promise对象的状态为rejected
//如果里面return内容那么内容将会传递给对应的then
async function fn1(){
throw new Error('错误')
// return '我是fn1'
}
fn1().then(res=>{
console.log(res);
},error=>{
console.log(error);
})
//await会使用当前的函数的线程占用 直到对应的修饰的promise执行完成
// await Promise.reject() 报错
利用async和await来解决回调地狱
function fn(v,delay) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(v);
resolve()
},delay);
})
}
async function fn1(){
await fn(1,1000)
await fn(2,2000)
await fn(3,100)
await fn(4,0)
console.log(5);
}
fn1()
同步代码执行比异步代码快
同步代码的执行是利用对应的js引擎解析的
异步代码执行是利用事件轮询机制执行的
事件轮询机制