1、null 和 undefined 有什么区别?
首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。
undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。
undefined 在 JavaScript 中不是一个保留字,这意味着可以使用 undefined 来作为一个变量名,但是这样的做法是非常危险的,它会影响对 undefined 值的判断。我们可以通过一些方法获得安全的 undefined 值,比如说 void 0。
当对这两种类型使用 typeof 进行判断时,Null 类型化会返回 “object”,这是一个历史遗留的问题。当使用双等号对两种类型的值进行比较时会返回 true,使用三个等号时会返回 false。
复制
1typeof null; // "object" (not "null" for legacy reasons)
2typeof undefined; // "undefined"
3null === undefined; // false
4null == undefined; // true
5null === null; // true
6null == null; // true
7!null; // true
8Number.isNaN(1 + null); // false
9Number.isNaN(1 + undefined); // true
2、ES5怎么实现继承
3、谈谈对 this 对象的理解
4、如何确保你的构造函数只能被new调用,而不能被普通调用?
5、object.assign和扩展运算法是深拷贝还是浅拷贝,两者区别是什么?
6、说说你对 Iterator, Generator 和 Async/Await 的理解
7、Promise.all 和 Promise.allSettled 有什么区别?
8、ES6中数组新增了哪些扩展?
9、怎么理解ES6中 Generator的?使用场景有哪些?内部有无return有何区别
10、你是怎么理解ES6中 Decorator 的?使用场景有哪些?
11、你是怎么理解ES6中Module的?使用场景有哪些?
12、说说你对 webpack5 模块联邦的了解?
13、如何实现浏览器内多个标签页之间的通信?
Broadcast Channel
顾名思义,“广播频道”,官方文档里的解释为“用于同源不同页面之间完成通信的功能”,在其中某个页面发送的消息会被其他页面监听到。
注意“同源”二字,该方法无法完成跨域的数据传输。
localStorage
localStorage是浏览器多个标签共用的存储空间,所以可以用来实现多标签之间的通信(ps:session是会话级的存储空间,每个标签页都是单独的)。
SharedWorker
SharedWorker可以被多个window共同使用,但必须保证这些标签页都是同源的(相同的协议,主机和端口号)
WebSocket通讯
全双工(full-duplex)通信自然可以实现多个标签之间的通信
定时器setInterval+cookie
- 在页面A设置一个使用setInterval定时器不断刷新,检查Cookies的值是否发生变化,如果变化就进行刷新的操作。
- 由于Cookies是在同域可读的,所以在页面B审核的时候改变Cookies的值,页面A自然是可以拿到的。
这样做确实可以实现我想要的功能,但是这样的方法相当浪费资源。虽然在这个性能过盛的时代,浪费不浪费也感觉不出来,但是这种实现方案,确实不够优雅。
postMessage
两个需要交互的tab页面具有依赖关系。
如 A页面中通过JavaScript的window.open打开B页面,或者B页面通过iframe嵌入至A页面,此种情形最简单,可以通过HTML5的 window.postMessage API完成通信,由于postMessage函数是绑定在 window 全局对象下,因此通信的页面中必须有一个页面(如A页面)可以获取另一个页面(如B页面)的window对象,这样才可以完成单向通信;B页面无需获取A页面的window对象,如果需要B页面对A页面的通信,只需要在B页面侦听message事件,获取事件中传递的source对象,该对象即为A页面window对象的引用:
1//B页面
2window.addEventListner('message',(e)=>{
3 let {data,source,origin} = e;
4 source.postMessage('message echo','/');
5});
postMessage的第一个参数为消息实体,它是一个结构化对象,即可以通过“JSON.stringify和JSON.parse”函数还原的对象;第二个参数为消息发送范围选择器,设置为“/”意味着只发送消息给同源的页面,设置为“*”则发送全部页面。
14、如何顺序执行10个异步任务?
解法1:for 循环 + await
简单的 for 循环是依次进行循环的,不像 Array.forEach,Array.map 方法是并发执行的,利用这一特点加 async / await 很容易写出下面这样的代码:
1(async () => {
2 const sleep = delay => {
3 return new Promise((resolve, reject) => {
4 setTimeout(_ => resolve(), delay)
5 })
6 }
7
8 const task = (i) => {
9 return new Promise(async (resolve, reject) => {
10 await sleep(500)
11 console.log(`now is ${i}`)
12 ++i
13 resolve(i)
14 })
15 }
16
17 let param = 0
18 for (let i = 0; i < 4; i++) {
19 param = await task(param)
20 }
21})()
输出:
now is 0
now is 1
now is 2
now is 3
解法2:Array.prototype.reduce
关于 Array.prototype.reduce 方法相信大部分小伙伴初见时都是用来数组求和。
reduce有初始值,积累值,以及当前值的概念。其中 积累值可以看作是前一个值,通过返回积累值又可以看作是 下一个值。使用reduce来解决问题的代码为:
1const sleep = delay => {
2 return new Promise((resolve, reject) => {
3 setTimeout(_ => resolve(), delay)
4 })
5}
6
7const task = (i) => {
8 return new Promise(async (resolve, reject) => {
9 await sleep(500)
10 console.log(`now is ${i}`)
11 ++i
12 resolve(i)
13 })
14}
15
16[task, task, task, task].reduce(async (prev, task) => {
17 const res = await prev
18 return task(res)
19}, 0)
输出:
now is 0
now is 1
now is 2
now is 3
可以这样理解 prev 和 task:
- prev:前一个 异步任务(promise)
- task:当前的异步任务
当前的异步任务需要上一个异步任务的结果作参数,故很显然要 await prev。
15、页面加载的过程中,JS 文件是不是一定会阻塞 DOM 和 CSSOM 的构建?
16、简单描述从输入网址到页面显示的过程
17、浏览器有哪几种缓存,各种缓存的优先级是什么样的?
18、什么是时间复杂度?
19、什么是 Samesite Cookie 属性?
20、Cookie 的 SameSite 属性有什么作用?
21、cookie 的有效时间设置为 0 会怎么样
22、什么是Typescript的方法重载?
在TypeScript中,方法重载(Method Overloading)是一种允许函数在不同参数数量或参数类型下具有不同的返回类型或行为的特性。这允许您以一种更灵活的方式定义函数,并根据传入的参数类型或数量来选择适当的行为或返回类型。
方法重载通常用于提供更加严格的类型检查和更好的类型推断,以及在代码中提供更清晰的接口。它使得函数可以根据不同的参数签名,提供不同的实现方式,而无需使用额外的运行时检查。
要定义方法重载,您需要按照以下步骤进行:
- 首先,定义一个函数的多个签名(overload signatures)。每个签名包含一个参数列表和一个返回类型。
- 然后,定义一个实际的函数体,这个函数体实现了多个签名所涵盖的不同情况。
这里有一个简单的例子,演示了如何在TypeScript中使用方法重载:
1function greet(name: string): string;
2function greet(age: number): string;
3function greet(value: string | number): string {
4 if (typeof value === "string") {
5 return `Hello, ${value}!`;
6 } else {
7 return `You are ${value} years old!`;
8 }
9}
10
11console.log(greet("Lydia")); // Output: "Hello, Lydia!"
12console.log(greet(30)); // Output: "You are 30 years old!"
上面定义了greet函数的两个不同的签名:一个接受string类型参数,另一个接受number类型参数。然后,我们实现了一个函数体,根据传入的参数类型进行相应的处理。
使用方法重载,TypeScript能够更好地检查函数调用,以确保传递的参数类型与预期的类型相符,并提供适当的类型推断,从而增加代码的类型安全性和可读性。