js

53 阅读7分钟

判断对象是不是空对象

- 通过JSON.stringify()判断
- Object.keys()判断
const obj = {};
console.log(JSON.stringify(obj) == '{}') //true
console.log(Object.keys(obj).length == 0) //true

延迟加载js脚本的几种方式

- `<script>`标签添加`defer`属性
- `<script>`标签添加`async`属性
- 使用setTimeout定时器延时加载
- 将js脚本放在文章底部,使其可能最后加载执行
- 对文章的加载事件进行监听,等加载完成后,再创建`<script>`标签来引入js脚本

image.png

参考链接:juejin.cn/post/706158…

console.log(['1', '2', '3'].map(parseInt))

输出结果是[1, NAN, NAN]

image.png image.png

image.png

参考链接:developer.mozilla.org/zh-CN/docs/…

typeof null

image.png

var

  • var的作用域只有:全局作用域、函数作用域
  • 预解析时,会把var和function声明的提前,赋值操作保留在原来位置。如果变量和函数同名,函数的声明更靠前
console.log(a);
var a = 1;
var a = function () {
  console.log(2);
}
function a() {
  console.log(3);
}
console.log(a);
// 输出
// f a() {...}
// f() {...}


// 预解析、执行过程如下
function a() { // 函数a声明提前
  console.log(3);
} 
var a
var a
console.log(a); //重复声明,不影响赋值操作
a = 1;
a = function () {
  console.log(2);
}
console.log(a);

非匿名立即执行函数

var b = 10;

(function b() {
   b = 20;
   console.log(b) //为什么输出的是b函数
})()

解释:
`立即执行函数``预解析`时被分成两部分:函数声明和();
变量重名时,函数声明更靠前
所以在声明完函数后,会立即调用该函数,故输出b函数

Promise

- Promise的状态

- pending(等待中)
- fulfilled(已成功)
- rejected(已失败)

- Promise的方法(都是并行执行)

- Promise.all():所有都成功,结果是成功;有一个失败,就是失败
- Promise.allSettled(): 等所有都执行完,不管成功还是失败
- Promise.any():返回第一个成功的结果。如果所有promise都失败了,则返回所有失败的结果。
- Promise.race(): 有一个状态变了,promise的状态就跟着变

image.png

let foo = await getFoo() ;.png

promise、try..catch()

new Promise((resolve, reject) => {
  reject(1);
  console.log(2);
  resolve(3);
  console.log(4);
}).then((res) => { console.log(res) })
  .catch(res => { console.log('reject1') })
try {
  new Promise((resolve, reject) => {
    throw 'error'
  }).then((res) => { console.log(res) })
    .catch(res => { console.log('reject2') })
} catch (err) {
  console.log(err)
}

// 输出结果是:2 4 reject1 reject2

// reject()或resolve()后,后面的代码还会运行
// Promise的状态只能被修改一次,如果后面还有修改状态的 会被忽略
// 一旦throw 'error', 后面的代码不会再执行
// 先reject('reject-1'); 再throw 'error': 会走Promise.catch,里面可以获取到reject的传参
// Promise里先resolve(),再throw 'error': 会走Promise.then。如果外面有try...catch, 也不会走catch
// Promise里只有throw 'error':会走Promise.catch,里面的可以获取到throw的信息
// Promise被reject()或throw 'error': 不会被外面的try...catch到,即使Promise没有.catch

async function f() {
  try {
    await new Promise((resolve, reject) => {
        throw 'err'
    })
  } catch (e) {
    console.log(e); // err  第二步
  }
  return await('hello');
}

const res = f();
console.log(res, 1); //log出promise对象  第一步

promise、async/await、Generator

  • async await使用上更为简洁,将异步代码以同步的形式进行书写,是处理异步编程的最终方案
  • promise编写代码相比Generator、async更为复杂,且可读性稍差
  • Generator、async需要和promise对象搭配使用
  • promise是es6, async await是es7
  • promise和async await是专门用来处理异步的
  • Generator并不是为异步而设计的,他还有其他功能(对象迭代、控制输出、部署Interator接口...)
  • async await实质上是Generator的语法糖,相当于是会自动执行的Generator函数
  • reject状态/throw报错的捕获
    • promise只能通过promise.catch()
    • async await通过try-catch,还可以通过promise.catch()
      • 把await语句放在try-catch里
      • await后面的 Promise 对象再跟一个catch方法
  • await后面的promise 如果rejected或报错,后面的代码不会继续执行

Generator.png

// 1
async function f() {
  const result = await new Promise((resolve, reject) => {
    resolve('resolve');
  })
  console.log(result); //resolve
  console.log('111'); //111
}
f()

// 2
async function f() {
  const result = await new Promise((resolve, reject) => {
    reject('reject');
  })
  console.log(result); //不执行
  console.log('111'); //不执行
}
f()

// 3
async function f() {
  const result = await new Promise((resolve, reject) => {
    reject('reject');
    throw 'err'
  })
  console.log(result); //不执行
  console.log('111'); //不执行
}
f()

// 4
async function f() {
  try {
    const result = await new Promise((resolve, reject) => {
      resolve('resolve');
    })
    console.log(result); //resolve
    console.log('111'); //111
  } catch (e) {
    console.log(e); // 不执行
  }
}
f()

// 5
async function f() {
  try {
    const result = await new Promise((resolve, reject) => {
      reject('reject');
    })
    console.log(result); //不执行
    console.log('111'); //不执行
  } catch(e) {
    console.log(e); // reject
  }
}
f()

// 6
async function f() {
  try {
    const result = await new Promise((resolve, reject) => {
      throw 'err'
    })
    console.log(result); //不执行
    console.log('111'); //不执行
  } catch (e) {
    console.log(e); // err
  }
}
f()

// 7
async function f() {
  try {
    const result = await new Promise((resolve, reject) => {
      resolve('resolve');
    }).then((res) => {
      console.log(res); //resolve
      return res;
    })
      .catch((e) => {
        console.log(e); //不执行
      })
    console.log(result); //resolve
    console.log('111'); //111
  } catch (e) {
    console.log(e); // 不执行
  }
}
f()

// 8
async function f() {
  try {
    const result = await new Promise((resolve, reject) => {
      reject('reject');
    }).then((e) => {
      console.log(e); //不执行
    })
      .catch((e) => {
        console.log(e); //reject
        return e;
      })
    console.log(result); //reject
    console.log('111'); //111
  } catch (e) {
    console.log(e); // 不执行
  }
}
f()

// 9
async function f() {
  try {
    const result = await new Promise((resolve, reject) => {
      throw 'err'
    }).then((e) => {
      console.log(e); //不执行
    })
      .catch((e) => {
        console.log(e); //err
      })
    console.log(result); //undefined
    console.log('111'); //111
  } catch (e) {
    console.log(e); // 不执行
  }
}
f()

Promise嵌套

// 第一题
// P1
new Promise(resolve => {
  console.log('P1 resolve')
  resolve()
}).then(() => {
  console.log('P1 then 1')
  // P2
  new Promise(resolve => {
    console.log('P2 resolve')
    resolve()
  }).then(() => {
    console.log('P2 then 1')
  }).then(() => {
    console.log('P2 then 2')
  })
}).then(() => {
    console.log('P1 then 2')
  })
// P1 resolve 
// P1 then 1
// P2 resolve
// P2 then 1
// 注意:此时 P1 的第一个 then 就算是执行完毕了,下面会执行 P1 的第二个 then
// P1 then 2
// P2 then 2

// 第二题
// P1
new Promise(resolve => {
  console.log('P1 resolve')
  resolve()
}).then(() => {
  console.log('P1 then 1')
  // P2
  return new Promise(resolve => {
    console.log('P2 resolve')
    resolve()
  }).then(() => {
    console.log('P2 then 1')
  }).then(() => {
    console.log('P2 then 2')
  })
}).then(() => {
    console.log('P1 then 2')
  })
// P1 resolve
// P1 then 1
// P2 resolve
// P2 then 1
// 注意:这里用了 return ,所以 P1 的第一个 then 执行完毕得等待 P2 完整执行完才算是执行完,才能 return 一个同步返回值回去
// 所以这里的结果跟上个例子不一样了
// P2 then 2
// P1 then 2

// 第三题
new Promise(resolve => {
  console.log('P1 resolve')
  resolve()
}).then(async () => {
  console.log('P1 then 1')
  // P2
  // 也等同于 return await P2
  await new Promise(resolve => {
    console.log('P2 resolve')
    resolve()
  }).then(() => {
    console.log('P2 then 1')
  }).then(() => {
    console.log('P2 then 2')
  })
}).then(() => {
    console.log('P1 then 2')
  })
// P1 resolve
// P1 then 1
// await 同上面的return
// P2 resolve
// P2 then 1
// P2 then 2
// P1 then 2

async await

执行到await时,被等待的表达式会立即执行,await下面的所有代码会推送进微任务队列。

queueMicrotask(() => {...}):Window 或 Worker的接口,将传入的函数加入微任务队列。遇到queueMicrotask()会直接执行,将函数放入微任务

async function foo() {
  console.log('11');
  await Promise.resolve().then(resolve => {
    console.log("1");
  });
  console.log(3);
}
foo();
console.log('33');
//输出:11,33, 1, 3
// 第一题
async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}

async function async2() {
  console.log('async2');
  new Promise((resolve, reject) => {
    resolve(1);
    console.log('async2---');
  });
}

async1();

new Promise(function (resolve) {
  console.log("promise1");
  resolve();
}).then(function () {
  console.log("promise2");
});
// 输出结果
// async1 start
// async2
// async2-- -
//   promise1
// async1 end
// promise2

// 第二题
new Promise((resolve, reject) => {
  console.log("promise1")
  resolve()
}).then(() => {
  console.log("then11")
  new Promise((resolve, reject) => {
    console.log("promise2")
    resolve()
  }).then(() => {
    console.log("then21")
  }).then(() => {
    console.log("then23")
  })
}).then(() => {
  console.log("then12")
})
// 输出
// promise1
// then11
// promise2
// then21
// then12
// then23

// 第三题
new Promise((resolve, reject) => {
  console.log("promise1")
  resolve()
}).then(() => {
  console.log("then11")
  new Promise((resolve, reject) => {
    console.log("promise2")
    resolve()
  }).then(() => {
    console.log("then21")
  }).then(() => {
    console.log("then23")
  })
}).then(() => {
  console.log("then12")
})
new Promise((resolve, reject) => {
  console.log("promise3")
  resolve()
}).then(() => {
  console.log("then31")
})
// 输出
// promise1
// promise3
// then11
// promise2
// then31
// then21
// then12
// then23

判断是宏任务还是微任务

  • 看发起源是谁:宿主(浏览器、node)发起的是宏任务,js引擎发起的是微任务
  • setTimeout里的回调函数是一个宏任务
  • 参考链接:blog.csdn.net/NancyFyn/ar…

数组方法

  • splice(): 改变原数组,就地移除或者替换已存在的元素和/或添加新的元素。
//start必填,其它参数可选
//item1、...、itemn:从 start 开始要加入到数组中的元素。
splice(start, deleteCount, item1, item2, /* …, */ itemN)
  • slice(): 返回一个新数组,这一对象是一个由 start 和 end 决定的原数组的浅拷贝(包括 start,不包括 end)
  • sort(): 改变原数组。
  • join()

数组去重

  • Array.from(new Set(arr))
  • reduce
const resultArr = arr.reduce((accumulator, currentValue) => {
  if (!accumulator.includes(currentValue)) {
    return [...accumulator, currentValue];
  }
  return accumulator;
}, []);
  • filter + indexof/findIndex
function unique(arr) {
  return arr.filter((item, index, array) => {
    return array.indexOf(item) === index;
  });
}

Map

  • map.has()
  • map.get()
  • map.set()
  • map.valuse()
  • Array.from(map.values())

call、apply、bind

apply(thisArg, argsArray)
call(thisArg, arg1, arg2, /* …, */ argN)
bind(thisArg, arg1, arg2, /* …, */ argN) //返回一个新函数