2022年被问到的前端面试题

402 阅读10分钟

第一次面试前端有点小紧张,面试官问的问题之前都有背过,但是由于紧张忘了怎么回答,所以保持好心态是前提 = =

1、状态码

HTTP状态码

1xx Informational(信息性状态码) 接受的请求正在处理

2xx Success(成功状态码) 请求正常处理完毕

(1)、200 OK: 表示从客户端发送给服务器的请求被正常处理并返回;

(2)、204 No Content:表示客户端发送给客户端的请求得到了成功处理,但在返回的响应报文中不含实体的主体部分(没有资源可以返回);

(3)、206 Patial Content:表示客户端进行了范围请求,并且服务器成功执行了这部分的GET请求,响应报文中包含由Content-Range指定范围的实体内容。

3xx Redirection(重定向) 需要进行附加操作以完成请求

(1)、301 Moved Permanently:永久性重定向,表示请求的资源被分配了新的URL,之后应使用更改的URL;

(2)、302 Found:临时性重定向,表示请求的资源被分配了新的URL,希望本次访问使用新的URL;

(3)、301与302的区别:前者是永久移动,后者是临时移动(之后可能还会更改URL)

(4)、303 See Other:表示请求的资源被分配了新的URL,应使用GET方法定向获取请求的资源;

(5)、302与303的区别:后者明确表示客户端应当采用GET方式获取资源

(6)、304 Not Modified:表示客户端发送附带条件(是指采用GET方法的请求报文中包含if-Match、If-Modified-Since、If-None-Match、If-Range、If-Unmodified-Since中任一首部)的请求时,服务器端允许访问资源,但是请求为满足条件的情况下返回改状态码;

(7)、307 Temporary Redirect:临时重定向,与303有着相同的含义,307会遵照浏览器标准不会从POST变成GET;(不同浏览器可能会出现不同的情况);

4xx Client error(客户端错误) 客户端请求出错,服务器无法处理请求

400 Bad Request:表示请求报文中存在语法错误;

401 Unauthorized:未经许可,需要通过HTTP认证;

403 Forbidden:服务器拒绝该次访问(访问权限出现问题)

404 Not Found:表示服务器上无法找到请求的资源,除此之外,也可以在服务器拒绝请求但不想给拒绝原因时使用;

5xx Server Error(服务器错误) 服务器处理请求出错

500 Inter Server Error:表示服务器在执行请求时发生了错误,也有可能是web应用存在的bug或某些临时的错误时;

503 Server Unavailable:表示服务器暂时处于超负载或正在进行停机维护,无法处理请求;

2、CSS居中

垂直居中的方式

行高=高

绝对定位 top50%,自身宽度的50%的负值

flex布局 align---center

水平居中的方式

绝对定位

flex布局 juest---center

margin 0 auto

text-align center

3、本地存储(如何解决刷新页面数据丢失)

本地存储的方式有哪些?区别及应用场景?

javaScript本地缓存的方法我们主要讲述以下四种:

  • cookie
  • sessionStorage
  • localStorage
  • indexedDB

区别

关于cookiesessionStoragelocalStorage三者的区别主要如下:

  • 存储大小:cookie数据大小不能超过4ksessionStoragelocalStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大
  • 有效时间:localStorage存储持久数据,浏览器关闭后数据不丢失除非主动删除数据; sessionStorage数据在当前浏览器窗口关闭后自动删除;cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
  • 数据与服务器之间的交互方式,cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端; sessionStoragelocalStorage不会自动把数据发给服务器,仅在本地保存

应用场景

在了解了上述的前端的缓存方式后,我们可以看看针对不对场景的使用选择:

  • 标记用户与跟踪用户行为的情况,推荐使用cookie
  • 适合长期保存在本地的数据(令牌),推荐使用localStorage
  • 敏感账号一次性登录,推荐使用sessionStorage
  • 存储大量数据的情况、在线文档(富文本编辑器)保存编辑历史的情况,推荐使用indexedDB

4、深拷贝和浅拷贝

浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝

如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址

JavaScript中,存在浅拷贝的现象有:

  • Object.assign
  • Array.prototype.slice()
  • Array.prototype.concat()
  • 使用拓展运算符实现的复制

深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性

常见的深拷贝方式有:

  • _.cloneDeep()
  • jQuery.extend()
  • JSON.stringify()
  • 手写循环递归

5、Promise

Promise构建出来的实例存在以下方法:

  • then() 是实例状态发生改变时的回调函数,第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数
  • catch() 用于指定发生错误时的回调函数
  • finally() 用于指定不管 Promise 对象最后状态如何,都会执行的操作

Promise构造函数存在以下方法:

  • all() 用于将多个 Promise实例,包装成一个新的 Promise实例
  • race() 同样是将多个 Promise 实例,包装成一个新的 Promise 实例
  • allSettled()
  • resolve()
  • reject()
  • try()

6、数组常用方法

下面前三种是对原数组产生影响的增添方法,第四种则不会对原数组产生影响

  • push() 接收任意数量的参数,并将它们添加到数组末尾,返回数组的最新长度
  • unshift() 开头添加
  • concat() 首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组,不会影响原始数组

下面三种都会影响原数组,最后一项不影响原数组:

  • pop() 删除数组的最后一项,同时减少数组的length 值,返回被删除的项
  • shift() 删除数组的第一项,同时减少数组的length 值,返回被删除的项
  • splice() 传入两个参数,分别是开始位置,删除元素的数量,返回包含删除元素的数组
  • slice() 创建一个包含原有数组中一个或多个元素的新数组,不会影响原始数组

即修改原来数组的内容,常用splice

传入三个参数,分别是开始位置,要删除元素的数量,要插入的任意多个元素,返回删除元素的数组,对原数组产生影响

即查找元素,返回元素坐标或者元素值

  • indexOf() 返回要查找的元素在数组中的位置,如果没找到则返回 -1
  • includes() 返回要查找的元素在数组中的位置,找到返回true,否则false
  • find() 返回第一个匹配的元素

7、 css选择器权重

!important -> 行内样式 -> #id -> .class -> 元素和伪元素 -> * -> 继承 -> 默认

8、 bind、call、apply 区别

call,apply,bind都是改变this指向函数的方法

区别:

  • call后面需要传参以逗号隔开 例如 fn.call(car,’奔驰’,福特’)

  • apply后面需要传参以数组形势 例如 fn.apply(car,[‘奔驰’,’福特’])

  • bind需要传参和call一样,将函数作为返回值但是不会执行fn 例如

  • let fun = fn.bind(car,’奔驰’,福特’)  fun()

image.png

9、Vue2和Vue3数据绑定的区别

原理:使用Object.defineProperty对象以及对象属性的劫持+发布订阅模式,只要数据发生变化直接通知变化 并驱动视图更新。

Vue2.0

语法:

Object.defineProperty(obj,  ``"name"``, { get:()=> {}, set:()=> {})

参数一: obj:劫持对象,参数二:"name":劫持对象属性 , 参数三:给属性添加set,get方法

例子:

let obj = { name:  "tom", age: 10 };

Object.defineProperty(obj,  "name", {

get: () => {

console.log("访问了name属性");

},

set: (newVule) => {

console.log("设置了name属性");

},

});

obj.name;  //触发get

obj.name = "jack";//触发set

vue3.0

原理:Vue3.0中的响应式采用了ES6中的 Proxy 方法。Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)

语法:

let p = new Proxy(obj,{get:(target,prop,p)=>{},set:(target, prop, vaule, p)=>{}})

参数一: target:劫持对象,参数二:prop:劫持对象属性 , 参数三:vaule:新的属性值, p:本身 列子:


let p = new Proxy(obj, {

get: (target, prop, p) => {

console.log("获取");

return prop  in target ? target[prop] : "默认值";

},

set: (target, prop, vaule, p) => {

console.log("设置");

target[prop] = vaule;

},

});
console.log(p.name);  //访问了name属性

console.log((p.name =  "java" ));  //设置了name属性

总结:

vue2通过Object.defineProperty劫持的是对象中每一个属性

vue3通过Proxy劫持的是对象中每一个属性

10、宏任务和微任务

什么是宏任务和微任务

  • 宏任务包括:setTimeout setInterval Ajax DOM事件
  • 微任务:Promise async/await
  • 微任务比宏任务的执行时间要早 image.png
代码

console.log(1)
 
setTimeout(function() {
  console.log(2)
}, 0)
 
const p = new Promise((resolve, reject) => {
  resolve(1000)
})
p.then(data => {
  console.log(data)
})
 
console.log(3)

image.png

结果是: 1, 3, 1000, 2

image.png

画的有点乱, 下面带你梳理一下执行顺序:
  • console.log(1) 是同步任务, 所以立即执行. (代码 ---> 执行栈 ---> 输出区域)
  • setTimeout是宏任务, 所以等微任务做完在执行. (代码 ---> 宏任务队列)
  • promise.then是微任务, 所以等主线程执行完毕在执行. (代码 ---> 微任务队列)
  • console.log(3) 是同步任务, 所以立即执行. (代码 ---> 执行栈 ---> 输出区域)
  • 现在主线程上面的任务全部执行完毕, 然后执行微任务队列的任务, 输出console.log(data)
  • 现在主线程上面没有任务, 微任务队列也没有任务, 这才这些宏任务队列, 输出console.log(2)
console.log(1)
setTimeout(function() {
  console.log(2)
  new Promise(function(resolve) {
    console.log(3)
    resolve()
  }).then(function() {
    console.log(4)
  })
})
 
new Promise(function(resolve) {
  console.log(5)
  resolve()
}).then(function() {
  console.log(6)
})
setTimeout(function() {
  console.log(7)
  new Promise(function(resolve) {
    console.log(8)
    resolve()
  }).then(function() {
    console.log(9)
  })
})
console.log(10)

这个代码太长, 画就很混乱, 直接梳理:

    1. console.log(1) 同步任务, 直接执行, 输出.
    1. setTimeout宏任务, 直接丢入宏任务队列.
    1. promise本身不是一个微任务, then才是; 所以console.log(5) 同步任务直接执行输出, 遇到then微任务, 丢入微任务队列
    1. setTimeout宏任务, 直接丢入宏任队列
    1. console.log(10) 同步任务, 直接执行, 输出.
    1. 主线程执行完毕, 再来执行微任务队列; 第一个进来的console.log(6) 执行输出
    1. 微任务队列执行完毕, 执行宏任务队列; console.log(2) 第一个进来执行输出, 下面console.log(3) 同步任务执行输出.
    1. 遇到then, 所以console.log(4) 丢入微任务队列
    1. 现在主线程是空的, 微任务队列中有console.log(4), 宏任务队列也有任务; 微任务优先级大于宏任务, 所以先执行console.log(4)
    1. 现在主线程是空的, 微任务队列也空了, 宏任务队列中还有第二个setTimeout
    1. console.log(7) 同步任务, 直接执行输出
    1. console.log(8) 同步任务, 直接执行输出
    1. 遇到then, console.log(9) 丢入微任务队列
    1. 主线程为空, 执行微任务队列, 输出console.log(9)
所以结果是: 1,5,10,6,2,3,4,7,8,9

image.png

参考地址:

zhuanlan.zhihu.com/p/422730888