JavaScript 中事件循环(eventloop)、垃圾回收机制、闭包、递归函数的理解及示例

事件循环(eventloop)

概念

js 是单线程,为防止阻塞代码,把同步代码交给 js 引擎执行 异步代码交给宿主环境,
同步代码放入执行栈中 异步代码等待时机送入任务队列中,
执行栈执行完毕 会去任务队列看是否有异步任务 有就送到执行栈执行 反复循环查看执行 这个过程就是事件循环

同步任务和异步任务(宏任务和微任务)

  • 同步:立即放入js引擎(js主线程)执行,并原地等待结果

  • 异步:先放入宿主环境(浏览器/node),不必原地等待结果,并不阻塞主线程继续往下执行,异步结果在将来执行

  • 宏任务:由宿主(浏览器、node)发起 setTimeout setTimeout不管时间是 0 还是 200 都是异步任务

  • 微任务:由 js 引擎发起 promise、async/await、Object.observe、process.nextTick(node) promise本身是同步,then/catch 的回调函数是异步的

执行顺序

先执行同步任务,在执行微任务,宏任务。
先进先出原则

例子

console.log(1);

setTimeout(() => {
		console.log(2);
}, 0)

console.log(3);

new Promise((resolve, reject) => {
		console.log(4);
		resolve(5);
}).then(res => {
		console.log(res);
}).catch(err => { })


console.log(6);
// 1 3 4 6 5 2

垃圾回收

常见浏览器垃圾回收算法:引用计数法(基本不再使用)和标记清除法

垃圾回收机制

js 中内存的分配和回收都是自动完成的,内存在不适用的时候会被垃圾回收器自动回收

内存泄漏

不再用到的内存,没有及时释放,就叫做内存泄漏

内存的生命周期

内存分配、内存使用、内存回收
全局变量一般不会回收,页面关闭回收
局部变量一般不用了,会被自动回收

闭包

概念

可以从内部函数访问外部函数的作用域

闭包的作用

缓存数据,延长作用域链

优点同时也是缺点:滥用闭包会造成内存泄漏

闭包的模式

  • 对象模式的闭包
  • 函数模式的闭包

基本写法

function closure() {
    var name = 'xr' // closure 局部变量
    function fn() { // closure 内部函数
        console.log(name); // 使用了父函数中声明的变量,此时形成了闭包
    }
    fn()
}
closure()

JavaScript 中事件循环(eventloop)、垃圾回收机制、闭包、递归函数的理解及示例_第1张图片

另一种写法

function closure() {
    var name = 'xr'
    return function fn() {
        console.log(name);
    }
}
closure()()

思考题

var name = 'window name'
var obj = {
    name: 'obj name',
    fun: function () {
        return function () {
            console.log(this.name);
        }
    },
    fun2: function () {
        var that = this
        return function () {
            console.log(that.name);
        }
    }
}

obj.fun()() // window name
obj.fun2()() // obj namedw

递归

概念

函数中调用函数自己 此时就形成了递归

递归一定要有结束条件 不然报错

例子

递归求和

function total(num) {
    if (num === 1) return 1 // 结束条件
    return num += total(num - 1) // 调用自己
}
console.log(total(3)); // 6

解析

  • 第一轮 3 + total(2)
  • 第二轮 3 + 2 + total(1)
  • 第三轮 3 + 2 + 1

对象深克隆

var obj = {
    name: "zs",
    list: [1, 2],
    detail: {
        msg: "123",
    },
};
var o = {};
function deepClone(newObj, oldObj) {
    for (var k in oldObj) {
        var item = oldObj[k];
        //   数组也属于对象所以要先在前面判断
        if (item instanceof Array) {
            newObj[k] = [];
            deepClone(newObj[k], item);
        } else if (item instanceof Object) {
            newObj[k] = {};
            deepClone(newObj[k], item);
        } else {
            newObj[k] = item;
        }
    }
}
deepClone(o, obj);
console.log(o);
o.detail.msg = "修改成功";
console.log(obj);

递归生成 tree 数据

JavaScript 中事件循环(eventloop)、垃圾回收机制、闭包、递归函数的理解及示例_第2张图片

let data = [
     { id: 1, name: "办公管理", pid: 0 },
     { id: 2, name: "请假申请", pid: 1 },
     { id: 3, name: "系统设置", pid: 0 },
     { id: 4, name: "权限管理", pid: 3 },
 ];
 function parentDeal(data, pid) {
     //声明返回数组
     let returnArr = [];
     data.forEach((item) => {
         if (item.pid === pid) {
             //除去最高层级的数据(id === 0)
             returnArr.push(item)
             //进入递归中处理 
             childrenDeal(data, item, item.id)
         }
     })
     return returnArr;
 }

 function childrenDeal(arr, itemData, itemId) {
     //首先判断是否有子类  没有默认为空
     itemData.children = itemData.children ? itemData.children : [];
     arr.forEach((item) => {
         //递归条件
         if (item.pid === itemId) {
             //找到则追加至上层数据children中
             itemData.children.push(item)
             //不断递归查找子类直到找不到子类本次递归结束才进入parentDeal函数进行下一最高层级操作
             childrenDeal(arr, item, item.id)
         }
     })
 }
 let resArr = parentDeal(data, 0)
 console.log(resArr)

你可能感兴趣的:(JavaScript,javascript,前端)