2022上半年面试总结

93 阅读10分钟

简单说下相关背景,2022年上半年离职开始找工作面试一直没整理,下面简单梳理下被问到的一些面试题。 目前在慢慢梳理,后续会继续补充。
我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情

1.es6

  1. let const var的区别
  2. for of
  3. 解构
  4. 箭头函数:
  • 箭头函数没有自己的this,箭头函数的this的指向就是函数声明时所在作用域this的值,用call方法也不能改变.
  • 箭头函数不能作为构造函数,意思就是不能对箭头函数使用new命令,否则会抛出错误
  • 不能够使用arguments对象
  1. class类
  2. 模板字符串:
 `你好${num}`
  1. 扩展运算符
  2. set、map:
  • set只有键值没有键名,类似数组、成员不能重复
  • map键值对
  1. export和import 模块

2.宏任务和微任务(event loop)

整体的script(作为第一个宏任务)开始执行的时候,会把所有代码分为两部分:“同步任务”、“异步任务”;

同步任务会直接进入主线程依次执行;

异步任务会再分为宏任务和微任务;

宏任务进入到Event Table中,并在里面注册回调函数,每当指定的事件完成时,Event Table会将这个函数移到Event Queue中;

微任务也会进入到另一个Event Table中,并在里面注册回调函数,每当指定的事件完成时,Event Table会将这个函数移到Event Queue中;

当主线程内的任务执行完毕,主线程为空时,会检查微任务的Event Queue,如果有任务,就全部执行,如果没有就执行下一个宏任务;

上述过程会不断重复,这就是Event Loop事件循环;

  • 微任务包括: promise 的回调、node 中的 process.nextTick 、对 Dom 变化监听的 MutationObserver。
  • 宏任务包括: script 脚本的执行、setTimeout ,setInterval ,setImmediate 一类的定时事件,还有如 I/O 操作、UI 渲染等。

3.闭包

funA 里面包含了 funB,而 funB 里面使用了 funA 的变量
闭包内如果没有特殊处理,函数的this指向window
作用:防抖节流,私有属性

var name = "window";
	var object = {
		name:"Ji de dian zan",
		getNameFunc: function(){
			return function(){
				return this.name;//this指向window
			}
		}
	}
console.log(object.getNameFunc()());//window
//经典题,如何输出1,2,3
for(var i = 0; i < 3; i++) {
    setTimeout(function() { 
        console.log(i); 
    }, 1000); 
}

4.三次握手 和四次挥手

5.http

  • http1.0 默认使用非持久连接,主要使用 If-Modified-Since、Expires 来做为缓存判断的标准
  • http1.1 默认使用持久连接(keep-alive)
    keep-alive降低拥塞控制,减少了后续请求的延迟。新引入了e-tag和If-None-Match来做为缓存判断的标准,新增了PUT、HEAD、OPTIONS 等方法
  • http2.0 二进制协议、多路复用头、信息压缩、服务器推送

6.http和https

HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议 https加密步骤

  • 客户端向服务器发起请求,请求中包含使用的协议版本号、生成的一个随机数、以及客户端支持的加密方法。

  • 服务器端接收到请求后,确认双方使用的加密方法、并给出服务器的证书、以及一个服务器生成的随机数。

  • 客户端确认服务器证书有效后,生成一个新的随机数,并使用数字证书中的公钥,加密这个随机数,然后发给服 务器。并且还会提供一个前面所有内容的 hash 的值,用来供服务器检验。

  • 服务器使用自己的私钥,来解密客户端发送过来的随机数。并提供前面所有内容的 hash 值来供客户端检验。

  • 客户端和服务器端根据约定的加密方法使用前面的三个随机数,生成对话秘钥,以后的对话过程都使用这个秘钥来加密信息。

7.当在浏览器中输入www.baidu.com并且按下回车之后发生了什么

  1. 解析url:协议主机名是否合法
  2. 缓存判断:请求资源是否过期
  3. DNS解析:判断是否有ip缓存
  4. TCP三次握手
  5. 发送HTTP请求
  6. 返回数据
  7. 页面渲染
  8. 四次挥手

8.强缓存和协商缓存

浏览器第一次加载资源,服务器返回200,从服务器下载资源文件,并缓存文件与响应头,以供下次加载时对比使用

下一次加载资源时,由于强制缓存优先级较高,先比较当前时间与上一次返回 200 时的时间差,如果没有超过 cache-control 设置的 max-age,则没有过期,并命中强缓存,直接从本地读取资源。如果浏览器不支持HTTP1.1,则使用 expires 头判断是否过期;

如果资源已过期,则表明强制缓存没有被命中,则开始协商缓存,向服务器发送带有 If-None-Match 和 If-Modified-Since 的请求;

服务器收到请求后,优先根据 Etag 的值判断被请求的文件有没有做修改,Etag 值一致则没有修改,命中协商缓存,返回 304;如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200;

如果服务器收到的请求没有 Etag 值,则将 If-Modified-Since 和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回 304;不一致则返回新的 last-modified 和文件并返回 200;

9.图片懒加载

10.数组的遍历方法有哪些,区别是什么

  • forEach():没有返回值,引用类型会改变原数组
  • map():不改变原数组,有返回值,返回新数组
  • filter():过滤数组,返回包含符合条件的数组
  • for...of:可遍历具有Iterator迭代器的对象
  • every() 和 some():some()只要有一个是true,便返回true;而every()只要有一个是false,便返回false
  • find() 和 findIndex():find()返回值;findIndex()返回的是第一个返回条件的值的索引值
  • reduce() 和 reduceRight():reduce()对数组正序操作;reduceRight()对数组逆序操作
    都不改变原数组

11.js继承

12.原型与原型链

js是用构造函数来新建一个对象的,每个构造函数都有一个prototype属性,包含了所有实例共享的属性和方法。当使用构造函数新建一个对象后,这个对象包含一个指针指向构造函数的prototype,这个指针就是对象的原型

当访问一个对象的属性的时候,如果这个对象内部不存在这个属性,那么就会去它的原型对象里找,一层一层的找下去形成一条链,称为原型链

13.垃圾回收

标记清除、引用计数(循环引用:对象属性相互引用,引用次数永远不会清0,只能手动置为null清空)

14.内存泄漏

循环引用setInterval没取消、闭包

15.Promise

  • all: 当传入的参数promise全部成功时,最后的结果才会成功(成功的结果是所有的promise的成功的结果组成的数组),只要有一个promise失败,all返回的实例就是一个失败的promise(失败的结果是传入的参数中的第一个失败的promise的结果)
  • race: 有一个成功,直接走race的resolve,如果有一个失败,直接走reject
  • allSettled:返回promises 集合,对于每个结果对象,都有一个 status 字符串。如果它的值为 fulfilled,则结果对象上存在一个 value 。如果值为 rejected,则存在一个 reason 。

16. call/apply/bind

call()接受的是一个参数列表,而apply()方法接受的是一个包含多个参数的数组。 连续调用bind,this指向第一个调用的指向,后面多次调用改变的是第一次函数返回的result指向

xx.call(obj, 3, 8) 
xx.apply(obj, [6, 8]) 
xx.bind(obj)(3, 8) 

17.浏览器内多个标签页之间的通信

  • 使用 websocket 协议
  • 使用 localStorage 的方式
  • 使用 postMessage 方法

18.Commonjs、Amd、Cmd、Umd、EsMoudle

nodejs出现之前,没有过于复杂的开发场景,所以是没有模块化的,后端才有。在nodejs之后就开始了commonjs的规范。

  • Commonjs
    一个文件就是一个模块,拥有单独的作用域,不会污染全局作用域;
    通过module.exports或者exports来暴露;
    通过require来加载模块;
    moudle.exports会覆盖exports
    可多次加载,但是只会第一次运行时加载,后面加载的都是缓存
暴露模块:moudule.exports = value; exports.xxx = value;
引入模块:const xxx = require('xxx')

commonjs用同步的方式加载模块。在服务端,模块文件都存放于本地磁盘,所以读取非常快。但是在服务端,由于网络的问题,应该用异步加载更合理。

  • AMD

AMD采用的是异步加载模块的方式,是一个浏览器端模块化的规范,需要用到require.js。所有这个模块的语句都定义在一个回调函数中,等到加载完成之后,这个回调函数才会执行。

用require.config()指定引用路径。用define()来定义模块用require来加载模块

// 执行基本操作
define('moduleName',['aa','bb'],function(ma, mb) {
    return xxx;
})

require(['aa', 'bb'], function(ma, mb) {
  // do something
 })

主要解决的问题 1.js文件多的时候可能会有依赖关系,而被依赖的文件需要优先加载
2.同步加载文件越多,页面失去响应时间越长

  • CMD

CMD是另一种模块化方案,它和AMD很类似,不同点在于:AMD推崇依赖前置,提前执行,而CMD推崇依赖就近,延迟执行,这个规范其实就是sea.js推广过程产生的。

  • UMD

一个整合了commonJS和AMD规范的方法。希望能解决跨平台模块的解决方案。
运行的原理:
UMD会先判断是否支持Node.js的模块(export)是不是存在。存在则使用node.js的模块方式。
再判断是不是支持AMD(define是不是存在。存在则使用AMD方式加载模块。

  • ESModule

实现了模块化功能,主要由两个命令构成:export和import。es6还提供了export default的命令

export xxx
export default {xx}

import {xxx} from 'xxx' //export
import xx from 'xx' //export default

总结 1.commonjs主要针对服务端,amd、cmd和esmodule主要针对浏览器端
2.amd和cmd都是异步加载,但是amd是预加载(加载某个模块前,会先将依赖模块加载完成),cmd则是懒加载,虽然一开始就异步加载好js文件,但是不会执行,而在需要的时候才执行
3.amd虽然是异步加载,但是加载顺序不一定,会导致出现一些问题。cmd只有在使用的时候才执行js,所以是可控的,但是js执行是同步的,所以在执行大文件的时候等待时间会很长
4.umd是amd和commonjs的糅合
5.ES6模块是动态引入的,并不会缓存值。
6.commonjs模块是对象,运行时加载,运行时才把整个模块挂载到export中。esmoudle不是对象,编译时加载,遇到import就会生成一个只读引用,等到运行时根据引用去加载取值,不会加载整个模块,仅取所需
7.commonjs是一个值的拷贝,esmoudle是值的引用

js先写到这吧,后续想起再补充