函数嵌套函数,内部函数拥有外部函数的引用,对应外部函数的变量或参数不会被gc回收。
1. 创建AO对象 (Activation Object 执行上下文) ,开辟的内存空间 (会在堆中开辟一个跟函数名
一样名字的空间)
2. 给函数里面的形参、变量进行赋值操作 (undefined)
3. 形参和实参同步
4. 找到函数声明 赋值给函数体
function fn(a=1,b=2){
console.log(a,b,c) //1,2,undefined
var c = function(){
console.log(1)
}
console.log(c) //函数
}
fn()
1. 创建GO对象 (Global Object 全局对象)(给对应的global对象添加属性)
2. 给函数里面的形参、变量进行赋值操作 (undefined)
3. 形参和实参同步
4. 找到函数声明 赋值给函数体
console.log(a) //function
var a = 10
function a(){}
console.log(a) //10 (全局污染)
function fn() {
let b = 22
var a = 20
a++
// console.log(a, b);
return a
}
fn()
//函数在执行中,会在堆中查找并将其推入栈中执行,执行完毕后会进行一个销毁操作
console.log(fn());
console.log(fn());
function fn(){
var i = 0
return function(){
i++ //标记为yes i也不会回收
console.log(i)
}
}
//闭包占用内存大 容易造成内存泄漏
var closureFn = fn() //接收一个函数
closureFn()//1
closureFn()//2
closureFn()//3
//解决内存泄漏
fn = null
从上述代码可以得到对应函数中return 一个引用数据类型 在这个引用数据类型内容保持对应的外部的一个参数或者是变量的引用那么这个变量将不会被回收。(扩大了函数内容变量的作用范围)
在规定时间内只执行一次 (执行最后一次)
// 在n秒内点击后,又在n秒内触发,n会重新计数,所以只会打印最后一次n秒执行完毕后的内容
function debounce(callback, delay) {
var timer = null
return function() {
// 清除上一次的延时器
clearTimeout(timer)
// 设置延时器
timer = setTimeout(() => {
callback()
// clearTimeout(timer)
}, delay);
}
}
var btn = document.querySelector('button')
var fn = debounce(function() {
console.log('点击了');
}, 1000)
btn.onclick = fn
在规定时间内执行第一次,执行完继续执行。(减少对应的次数)
// 在n秒内点击后,n秒内再点击不会触发,n秒内只执行一次
function throttling(callback, delay) {
var flag = false
return function() {
clearTimeout(timer)
if (!flag) {
var timer = setTimeout(() => {
callback()
console.log(delay);
flag = false
}, delay);
}
flag = true
}
}
var btn = document.querySelector('button')
var fn = throttling(function() {
console.log('点击了');
}, 3000)
btn.onclick = fn
概述:将一个多参数的函数 分成多个函数(彼此之间可以任意组成)
核心:参数个数没到对应的个数返回的是函数 参数个数到了返回的是值
普通函数、函数柯里化、高阶函数柯里化 对比如下:
//普通函数
function sum(a, b, c, d) {
return a + b + c + d
}
console.log(sum(1, 5, 3, 2)); //11
// 函数柯里化
function carry(a) {
return function(b) {
return function(c) {
return a + b + c
}
}
}
console.log(carry(1)(1)(1)); //3
console.log(carry(5, 3, 2)); // f(b)
console.log(carry(2)(5)); //f(c)
console.log(carry()()()); //NaN
// 高阶函数柯里化
function carrying(fn) {
let args = Array.prototype.slice.call(arguments, 1)
return function() {
let allargs = args.concat([...arguments])
if (allargs.length < fn.length) {
return carrying.call(this, fn, ...allargs)
} else {
return fn.apply(this, allargs)
}
}
}
let fn = carrying(sum)
console.log(fn(1, 2, 3, 6)); //12
console.log(fn(5, 4)(1)(5)); //15
console.log(fn(5, 3, 6)(8)); //22
promise 是 ES6 新增的一个类,翻译为承诺,它是用于解决异步问题的(替代回调函数)。
//传入函数来进行构建 传入的函数内有俩个参数传递 (resolve、reject都是函数)
//new Promise是同步执行的代码 它的里面可以包含异步代码
new Promise((resolve,reject)=>{
console.log('hello') //也是同步的
})
原型方法:then、catch、finally
then :处理对应的一个promise状态变化的
let promise = new Promise((resolve,reject)=>{
console.log('hello')
//promise的状态是唯一的
// resolve(123) //成功状态
// return 123 //状态没有发生变化 不会调用then
// reject(456) //拒绝状态
throw new Error('你好错了')
//then方法 它里面传入俩个参数 (都是函数)
//第一个参数为成功的处理函数(携带 resolve函数传递的数据 相当于接收了return的数据return也会调用的对应的then)
//第二个参数为拒绝的处理函数(携带 reject函数传递的参数 或者 捕获抛出的错误)
}).then((result)=>{
console.log(result)
},(err)=>{
console.log(err)
})
//then的传值 使用return
new Promise((resolve)=>{
resolve()
}).then(()=>{
return 123
}).then((result)=>{
console.log(result)//123
})
//then的值穿透 发生在上层的then方法里面没有函数为参数
new Promise((resolve)=>{
resolve('hello')
})
// .then(()=>{}) 只有有参数不会发生值传统
.then()
.then()
.then((result)=>{
console.log(result)//123
})
catch :捕获 promise 错误以及获取对应的 promise 的 reject 方法调用的结果(跟 then 方法中的第二个参数一模一样)
new Promise((resolve,reject)=>{
// reject(11)
throw new Error('我错了')
}).catch((err)=>{ //接收reject函数调用的参数 或者捕获对应的错误
console.log(err)
})
//catch也会发生值穿透
new Promise((resolve,reject)=>{
// reject(11)
throw new Error('我错了')
}).catch()
.catch()
.catch((err)=>{ //接收reject函数调用的参数 或者捕获对应的错误
console.log(err)
})
finally :状态发生变化就会调用的函数
//finally 不管成功还是失败都会调用的函数(状态变化)
new Promise((resolve,reject)=>{
resolve(111)
// reject(11)
// throw new Error('我错了')
}).finally(()=>{
console.log('完成了')
})
静态方法:resolve、reject、race、all、allsettled
resolve :产生一个状态为成功的 promise 对象
//返回成功状态的promise resolve
let promise1 = Promise.resolve(456)
console.log(promise1)
promise1.then((result)=>{
console.log('成功了'+result)
})
reject :产生一个状态为拒绝的 promise 对象
//reject方法 产生一个拒绝状态的promise
let promise2 = Promise.reject(123)
console.log(promise2)
promise2.catch((err)=>{
console.log(err)
})
race :竞速 (传入一个 promise 数组 返回执行完成最快的 promise)
//竞速方法race 比较执行速度 谁先执行完(不区分成功失败)返回执行快的promise
let promise3 = Promise.reject(1)
let promise4 = Promise.reject(2)
// let promise3 = Promise.resolve(1)
let newPromise = Promise.race([promise3,promise4]) //成功状态比拒绝状态要快
console.log(newPromise)
all :并行执行传入 promise 数组 (遇到了rejected 那么就获取到 rejected 的 promise,如果全部成功会接收所有的 promise 结果)
//all 同步并行执行多个promise 返回一个promise ( 全部成功 包含所有的结果 状态为成功)
// (如果遇到了拒绝那么返回的就是拒绝状态的 只会接收到拒绝传递的值)
let promise5 = Promise.reject(5)
let promise6 = Promise.reject(6)
let promise7 = Promise.reject(7)
// let promise7 = Promise.resolve(7)
let promise8 = Promise.reject(8)
let promiseAll = Promise.all([promise5,promise6,promise7,promise8])
console.log(promiseAll)
allsettled :并行执行传入promise数组 (只要执行完成那么返回都是对应的成功状态,且会接收所有的promise结果)
//allSettled 并行执行多个promise 返回所有的结果 (只要执行完成那么状态就是成功) 新增的
let promiseAllsettled =
Promise.allSettled([promise5,promise6,promise7,promise8])
console.log(promiseAllsettled)
问题提出:异步代码如何同步执行,使用回调函数,但回调函数嵌套过深会导致回调地狱问题
//回调函数解决的问题
function fn(message, delay = 0, callback) {
setTimeout(() => {
console.log(message)
callback()
}, delay)
}
//这个代码没有任何问题,但是这个代码的可维护性低,可读性低(回调地狱)
//这个代码没有可用性(避免回调函数不能嵌套过深)
fn('1', 1000, () => {
fn('2', 500, () => {
fn('3', 1000, () => {
fn('4', 2000, () => {
fn('5', 100, () => {
fn('6', 1000, () => {
// ....
})
})
})
})
})
})
使用 promise 来解决对应的回调地狱
核心:在对应的 then 方法返回一个新的 promise 再调用下一个 then
//resolve 触发成功的函数 对应的处理的方法 then
//reject 触发失败的函数 对应的处理的方法 catch
new Promise((resolve, reject) => {
setTimeout(() => {
console.log(1);
//调用成功的函数
resolve()
}, 1000)
}).then(() => {
//在then方法里面通过返回对应的新的promise来调用下一个then
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log(2);
resolve()
}, 500)
})
}).then(()=>{
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log(3);
resolve()
}, 500)
})
}).then(()=>{
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log(4);
resolve()
}, 200)
})
})
async及awiat
【注意事项】
//async用于修饰对应的函数的异步
async function sayHello(){
console.log('123')
//因为它返回的值,在async修饰的函数内容,返回内容相当于调用了resolve方法,更改状态为成功
//报错相当于调用了reject
// throw new Error() 相当于reject调用
//函数默认返回undefined
// return 123 相当于resolve调用
}
//async修饰的函数调用会返回一个promise对象
let promise = sayHello()
console.log(promise)
promise.then((result)=>{
console.log(result)
})
async function say(){
//使当前js引擎线程等待 等待对应的状态更改才释放
await new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log(1);
resolve()
},2000)
})
console.log(2)
}
say() // 1 2
async function test(){
//使当前js引擎线程等待 等待对应的状态更改才释放
await new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log(1);
resolve()
},2000)
})
await new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log(2);
resolve()
},1000)
})
await new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log(3);
resolve()
},500)
})
console.log(4)
}
test()
eventLoop事件轮询,针对于对应的异步任务的执行相关操作(定时器、事件、请求....)。
队列是先进先出一个数据结构,事件队列就是其异步任务的一个队列(先进去先执行 后进行后执行)
栈是一个先进后出的一个数据结构,它主要用执行对应的js代码。
宏任务 (大的任务 线程直接分配的)
微任务 (小的任务)
宏任务进入宏任务队列 微任务进入微任务队列
eventLoop主要是控制宏任务队列及微任务队列的任务执行,也就是等待和发送消息或事件的程序结构