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()
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
解析
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);
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)