前端八股文经验分享:面试拷打经历 与 知识总结(纯个人总结)(一) - 持续更新ing

289 阅读18分钟

1. 数组扁平化的方法

Ex. var arr=[1,[2,[3,[4,5]]]];  =>  arr=[1,2,3,4,5]

  1. 传统方法 递归
  2. 使用reduce函数递归遍历
  3. 数组强制类型转换
    对于数组对象,toString方法连接数组并返回一个字符串,其中包含用逗号分隔的每个数组元素。返回的字符串使用split分割成子字符串数组,最后将数组中每个元素的类型转换为Number
  4. 使用ES6的flat方法 flat(depth)
  5. 使用JSON的函数正则表达式 使用JSON的序列化函数stringify()先对数组进行序列化,再用正则去掉[],得到的结果在最外层加上[]后使用JSON.parse()恢复成数组对象。
  6. 扩展运算符与some函数结合
    先用some方法把数组中仍然是数组的项过滤出来,再执行concat操作,利用ES6的扩展运算符‘ ... ' 将其拼接到原数组中,最后返回。

2. CSS两列布局的实现方式

  1. float+calc() : 左列开启浮动+右列开启浮动+右列宽度为父级100%减去左列宽
  2. float+margin-left :左列开启浮动+右列增加外边距
  3. absolute+margin-left :开启定位脱离文档流+(同上)
  4. float+overflow : {overflow:hidden}
  5. flex布局:.container {display:flex}       .right {flex:1}
  6. grid布局

3. BFC

一、什么是BFC? 

        一个块格式化上下文(block formating context)是Web页面得可视化CSS渲染出得一部分,它是块级盒布局出现的区域,也是浮动元素进行交互的区域

二、触发条件

  1. 浮动元素,float不是none
  2. 绝对定位元素元素具有position为absolute或fixed
  3. 内联块,元素具有display:inline-block
  4. 表格单元格,元素具有display:table-cell
  5. 表格标题,元素具有display:table-caption
  6. 具有overflow且值不是visible的块元素
  7. display:flow-root
  8. column-span:all 应当总是会创建一个格式化上下文,即便具有column-span:all 的元素并不被包裹在一个多列容器中

三、BFC特性

  1. 内部的Box会在垂直方向上一个接一个的放置
  2. 垂直方向上的距离由margin决定
  3. BFC的区域不会与float的元素区域重叠
  4. 计算BFC的高度时,浮动元素也参与计算
  5. BFC就是页面上的一个独立容器,容器里面的子元素不会影响外面元素

四、为什么要使用BFC

  1. BFC可以解决子元素浮动导致父元素高度塌陷的问题
  2. BFC可以解决两个兄弟盒子之间的垂直距离是由他们的外边距所决定的,以较大为准
  3. 不被浮动元素覆盖
  4. 防止文字环绕

4. 水平居中方式

  1. margin:auto; 元素有宽度有高度时

  2. position:absolute; 元素有宽度有高度时,设置position和margin为负的宽高的一半

    position:absolute; 元素有宽度有高度时,利用calc计算top和left
    position:absolute; 元素宽度、高度未知时,设置position和transform:translate(-50%, -50%)

  3. 弹性盒子:为其父元素设置display:flex

  4. 利用水平对齐和行高:设置text-alignline-height,实现单行文本水平垂直居中

  5. grid:在网格项目中设置justify-self, align-self 或者 margin:auto
    grid:在网格容器上设置justify, align-items或者jsutify-content, align-content

5. Vue-Router的原理,两种模式

一、hash模式——即地址栏URL中的 # 符号

  1. hash不会被包含在HTTP请求中,对后端完全没有影响,因此改变hash不会重载页面
  2. 404错误:仅hash符号之前的内容会被包含在请求中,即使没有做到对路由的全覆盖也不会返回404错误
  3. hash的原理是采用hashchange事件,可以在window监听hash的变化,我们在url后面随便添加一个 #xx 触发这个事件

二、history模式

  1. 需要特定浏览器支持,有back,forward,go,pushState等方法,提供了对历史记录修改的功能,当它们执行时,虽然改变了当前url,但浏览器不会立即向后端发送请求
  2. 404错误:前后端发起请求的url需一致,返回404错误
  3. histor的原理是H5的几个新API

6. 全局路由守卫和组件路由守卫

一、全局守卫

  1. 全局前置守卫 beforeEach
    router.beforeEach((to, from, next) => {
    })
    在路由跳转之前被触发
  2. 全局解析守卫 beforeResolve
    参数: to, from, next
    在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用
  3. 全局后置钩子 afterEach
    参数:to, from, failure

二、组件内路由守卫

  1. beforeRouteEnter: 不能访问this,因为守卫在导航确认之前被使用,因此即将登场的新组件还没被创建
  2. beforeRouteUpdate: 主要是路由复用时被调用,即在当前页面跳转页面,会走该路由,而不会重头
  3. beforeRouteLeave: 这个离开路由守卫通常用来禁止客户在未保存修改前突然离开,该导航可以通过next(false)来取消

注意:beforeRouteEnter是支持给next传递回调的唯一守卫,对于beforeRouteUpdate和beforeRouteLeave来说,this已经可用了,所以不支持传递回调,因为没有必要了。

7. some和every方法的区别

相同点:

  • 都可以遍历数组每一项数据
  • 都不会对空数组进行检测
  • 都不会改变原始数组

不同点:

  • some() 方法会依次执行数组的每个元素
    如果有一个元素满足条件,则表达式返回true,剩余的元素不会再执行检测
    如果没有符合条件的元素,则返回false
  • every() 方法使用指定函数检测数组中的所有元素
    如果数组中检测到有一个元素不满足,则整个表达式返回false,且剩余的元素不会再进行检测;如果所有元素都满足条件,则返回true

8. forEach 和 map 的区别

相同点:

  • 都是循环遍历数组中的每一项
  • 每次执行匿名函数都支持三个参数,参数分别为item(当前每一项), index(索引值), arr(原数组)
  • 匿名函数的this都指向window
  • 只能遍历数组

不同点:

  • map() 方法会得到一个新数组并返回;forEach() 会修改原来的数组
  • forEach() 允许callback 更改原始数组的元素;map() 返回新的数组

使用场景:

  1. forEach() 适合你并不打算改变数据的时候,而只是想用数据做一些事情——比如,存入数据库或打印
  2. map() 适合你要改变数据值的时候,不仅在于它更快,而是返回一个新数组,可以搭配filter(), reduce() 等

9. 浅拷贝 和 深拷贝

一、浅拷贝——拷贝深度不够会改变原数组

push、pop、unshift、shift、reverse、sort、forEach、Object.assign(第一个参数是拷贝的目标对象,后面的参数是开呗的来源对象)、扩展运算符

二、深拷贝——不会改变原数组,增加了一个新指针并申请了一个新元素地址

slice、concat、map、filter、reduce、for...in...、使用JSON.parse和JSON.stringify

注意:基本类型(string, number, boolean, null, undefined, symbol)不存在深浅拷贝问题,因为赋值的是数据;引用类型(Object, Array, Date, RegExp, Function)存在这个问题

10. reduce 方法

定义:reduce() 方法接收一个函数作为累加器,数组中的每个值(从左至右)开始缩减,最终计算为一个值
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

reduce的常用方法:

  • 数组求和
  • 累加数组中对象的值
  • 计算数组中每个元素出现的次数
  • 数组去重
  • 二维数组变一维
  • 将多维数组变一维
  • 根据属性把对象分类

11. 事件循环机制

浏览器时间循环node.js事件循环

Event Loop:同步任务+异步任务

所有同步任务都在主线程上执行,形成一个函数调用栈(执行栈),而异步任务则先放到任务队列里,任务队列又分为宏任务和微任务。

宏任务:script(整块代码)、setTimeout、setInterval、I/O,UI交互事件、setImmediate(node环境)
微任务:new promise().then 回调、MutationObserver(h5新特性)、process.nextTick(node环境)

12. 闭包

定义:有权访问其他函数作用域中变量得函数

JS中,变量得作用域属于函数作用域,在函数执行完毕后,它得作用域会被销毁,内传也会被回收,但由于闭包在函数内部创建一个子函数,且子函数可以访问父级函数中得作用域,即父函数执行完作用域也不会被回收,这就是闭包。

缺点:比普通函数更见占用内存,可能会造成内存泄漏

13. 箭头函数

语法比函数表达式更加简洁,并且没有this, arguments, super 或 new.target;更加适用于本来需要隐匿函数的地方,并且它不能用作构造函数。

14. this指向

  1. 普通函数中,this指向window
  2. 构造函数中,this指向创建对象
  3. 方法声明中,this指向调用者
  4. 定时器中,this指向window
  5. 事件中,this指向事件源

15. 作用域有哪些

全局作用域        函数(局部)作用域        块级作用域        静态作用域        动态作用域

16. JS获取DOM节点的方式

getElementById        getElementByClassName        getElementByTagName

querySelector & querySelectorAll                              getElementByName

document.title & document.body

17. CSS布局

静态布局        自适应布局        流式布局        响应式布局        弹性布局

18. 双向绑定的原理

通过数据劫持结合发布订阅模式的方法来实现

19. Vue2 和 Vue3 的区别

一、Composition API

        Vue2是选择式API;Vue3是组合式API

二、双向数据绑定原理的变化

        Vue2利用数据劫持结合订阅发布 Object.defineProperty();Vue3使用ES6的Proxy API对数据代理

三、Vue3支持碎片

四、建立数据

        Vue2放入data;Vue3需使用setup(),在组件初始化构造的时候触发

五、生命周期钩子不同

六、父子传参不同

七、Vue3新增Teleport瞬移组件

20. HTTP 和 HTTPS 的区别

  1. https需要到CA申请证书,一般免费证书较少,需要一定费用
  2. http是超文本文本传输协议,信息是明文https是具有安全性的ssl加密传输协议
  3. 连接方式不同,用的端口不一样,前者是80,后者是443
  4. http的链接是无状态的;https协议是有ssl+http协议构建的可进行加密传输,身份认证的网络协议

21. 用elementUI的时候,如果需要el-button,打包的时候怎么按需打包

按需引入,借助babel-plugin-component打包

22. tree shaking(摇树优化)

ES6推出tree shaking,当我们在项目中引入其他模块时,它会自动将我们用不到的代码,或者永远不会执行的代码摇掉,在Uglify阶段查出,不打包到bundle中。

23. 为什么组件库按需加载时使用babel插件实现而不是依赖tree-shaking

tree-shaking依赖ES module语法,webpack不支持导出ES module。

组件库都是用webpack开发,不支持ES module导出

24. 浏览器渲染页面的过程

  1. 渲染引擎首先通过网络获得请求文档的内容
  2. 解析HTML文件,构建DOM Tree
  3. 解析CSS,构建CSSOM Tree(CSS规则树)
  4. DOM TreeCSSOM Tree合并,构建Render Tree(渲染树)
  5. reflow(重排):根据Render Tree进行节点信息计算(Layout)
  6. repaint(重绘):根据计算好的信息绘制整个页面(Painting)

25. JS 和 CSS 会不会阻塞页面渲染

  1. 通过style标签引入的样式和同步加载link标签会阻塞页面渲染,但异步加载link标签则不会
  2. js脚本通过添加asyncdefer的方法来开启异步下载,开启异步下载则不会阻塞页面渲染,但下载完成后,加async的脚本会立即执行,执行时会阻塞页面渲染;
    而加defer的脚本会等样式dom结构加载完成后才会执行,此时页面已经渲染完了,所以只有同步脚本和个别情况下加了async的脚本会阻塞渲染

26. 手写防抖和节流

防抖

function debounce(fn,wait){
    let timer = null;
    return function(){
        if (timer) {
            clearTimeout(timer)
            timer = null
        }
        timer = setTimeout(()=>{
            fn.call(this, arguments)
        },  wait)
    }
}

节流

function throttle(fn, wait){
    let timer = null
    return function(){
        if(!timer){
            timer = setTimeout(()=>{
                fn.call(this,arguments)
                tiemr = null
            }, wait)
        }
    }
}

27. 三次握手,四次挥手

三次握手: 指建立一个TCP连接时,需要客户端和服务端总共发送3个包,以确认双方的接受能力和发送能力是否正常,为后面的可靠性传送做准备

四次挥手: 终止TCP链接只需要发送4个包,客户端或服务端均可主动发起挥手动作

28. 状态码

  • 1XX (信息性状态码)                        表示接受的请求正在处理
  • 2XX (成功性状态码)                        表示请求正常处理完毕
  • 3XX (重定向状态码)                        表示需要附加操作以完成请求
  • 4XX (客户端错误状态码)                 表示服务器无法处理请求
  • 5XX (服务端错误状态码)                 表示服务器处理请求出错

29. 手写对象扁平化

const flatten = (arr) => {
    return arr.reduce((pre, cur) => {
            return pre.concat(Array.isArray(cur)? flatten(cur) : (cur)
      }, [])
}

30. setTimeout 实现 setInterval

setTimeout(function f() {
    setTimeout(f,interval); 
}, interval)

31. 水平垂直居中方法

  1. flex布局,父元素:display:flex; justify-content: center; align-items: center;
  2. 子绝父相,子元素:left:50%; top:50%; transform: translate(-50%, -50%)
  3. 子绝父相,子元素:left:0; top:0; botton:0; right:0; margin: auto
  4. 文字的话,text-align:center; line-height 和 height 相等

32. Promise.allSettled()

用来确认一组异步操作是否全都结束了,包含了“fulfilled” 和 “rejected” 两种情况
Promise.allSettled() 方法接受一个数组作为参数,数组每个成员都是一个Promise对象,并返回一个新Promise对象,只有等到参数数组的所有Promise对象都发生状态变更(不管是fulfilled还是rejected),返回的Promise对象才会发生状态变更

33. 盒子模型分哪两种

  • W3C标准的盒子模型(标准盒模型)
  • IE标准的盒子模型(怪异盒模型)

34. 输入url后会发生什么

  1. 浏览器向DNS服务器请求解析该URL中的域名所对应的IP地址
  2. 解析出IP地址后,根据该IP地址和默认端口80,和服务器建立TCP连接
  3. 浏览器发出读取文件(URL域名后面部分对应的文件)的HTTP请求,该请求报文作为TCP三次握手的第三个报文的数据发送给服务器
  4. 服务器请求作出回应,并把对应的html文本发送给浏览器
  5. 释放TCP连接
  6. 浏览器将该html文本显示内容

35. 手写ajax(使用promise封装)

function getJSON(url) {
  let promise = new Promise((resolve, reject) => {
    let xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onreadystatechange = function () {
      if (this.readyState !== 4) return;
      if (this.status === 200) {
        resolve(new Error(this.statusText));
      } else {
        reject(new Error(this.statusTzext));
      }
    };
    xhr.onerror = function () {
      reject(new Error(this.statusText));
    };
    xhr.responseType = 'json';
    xhr.setRequestHeader('Accept', 'application/json');
    xhr.send(null);
  });
  return promise;
}

36. 前端有什么安全性问题

  • XXS攻击(跨站脚本攻击)
  • CSRF安全漏洞(跨站请求伪造)
  • 文件上传漏洞
  • 限制URL访问,越权访问
  • 不安全的加密存储
  • SQL注入攻击
  • OS命令注入攻击

37. 面向对象的继承方法

  1. 原型对象
  2. 原型链继承
  3. 空函数作为中介继承
  4. 绑定继承
  5. 组合继承
  6. 拷贝继承
  7. ES6的class继承

38. 手写一个组合继承

function superType() {}
function subType() {
  //构造函数继承
  superType.call(this, ...arguments);
}
//原型链继承
subType.prototype = new superType();
//对象增强
subType.prototype.constructor = subType();

39. defer 和 async 的区别

一、<scriptasyncsrc=script.js></script><script async src = 'script.js'></script>

        有async,加载和渲染后续文档元素的过程将和script.js的加载与执行异步

二、<scriptdefersrc=myscript.js></script><script defer src='myscript.js'></script>

        有defer,加载后续文档元素的过程将和script.js的加载异步,但是script.js的执行要在所有元素解析完成之后,DOMContentLoaded事件触发之前完成

40. 工厂模式的理解

工厂模式:主要是用来实例化有共同接口的类,它可以动态的决定应该实例化哪一类
主要分为三种形态:简单工厂模式工厂方法模式抽象工厂模式

一、简单工厂模式

        主要有一个静态方法,用来接收参数,并根据参数进行switch或if判断来决定返回实现同一接口的不同类的实现

二、工厂方法模式

        把工厂类定义为接口,以多态的形式来削弱工厂类的职能,对简单工厂进一步的解耦,降低简单工厂模式的风险,提高可维护性,可扩展性

三、抽象工厂模式

        工厂模式下一个工厂只能生产同类同品 的产品,而抽象工厂模式下一个工厂可以生产多类同品 的产品

41. $nextTick 的使用场景

  • 在vue生命周期的created()里进行DOM的操作一定要使用nextTick(),因为created执行的时候DOM还未渲染
  • 在方法里操作DOM,由于dom元素还没有更新,因此打印出来的还是为改变之前的值,而通过this.$nextTick()获取到的值为dom更新之后的值

42. Vue2 数据发生变化到页面变化的基本流程

  1. 先将数据进行Obj.defineProperty() 进行绑定,判断数据为数组或者对象进行绑定
  2. 当页面开始渲染会定义updateComponent方法,这个方法主要就是为了调用render方法
  3. 进入render的时候会执行页面使用的值,这时候会触发该数据的get属性
  4. 开始进行绑定依赖
  5. 之后通过patch方法将节点进行更新替换或者新增
  6. 如果数据发生变化,会执行数据的set方法,这时数据的Dep.notify会调用
  7. Dep.notify会去调用绑定的Watcher,促使它更新,并收集所有改变,一次性进行改变
  8. 调用Watcherrun()方法,run方法会调用updateComponent方法进行render更新

43. vue中v-for如何实现对数组、对象、数字的遍历

数组:v-for="(item, index) in/of arr"
对象:v-for="(value, index) in obj“
数字:v-for="(item,index) in 数字"         index从1开始

44. 哪些因素会影响重排重绘

  1. 页面首次进入渲染
  2. 浏览器resize
  3. 元素位置和尺寸发生改变
  4. 可见元素的增删
  5. 内容发生改变
  6. 字体font改变
  7. CSS伪类激活

45. GET 和 POST 的区别

GETPOST
get参数在请求地址post参数在请求体
get有长度限制post没有长度限制
get有缓存/
get返回的结果不会变post结果可能不一样

46. HTTP请求的几种类型

GET、POST、OPTIONS、PUT、DELETE、HEAD

47. HTTP缓存的方式

一、强制缓存

        指只要浏览器缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边

二、协商缓存

        与服务端协商之后,通过协商结果来判断是否使用本地缓存

48. 浏览器的存储方式

1)属于文档对象模型:documentcookie
2)属于浏览器对象模型:localStroagesessionStorageindexDB

区别:

  1. cookie在浏览器和服务器间来回传递,而sessionStoragelocalStorage不会自动把数据传给服务器,仅在本地缓存
  2. 存储大小限制不同,cookie数据不能超过4K,同时每次http请求都会携带cookie,所以cookie只适合保存很小的数据。
    sessionStoragelocalStorage虽然也有存储大小限制,但比cookie大很多,可以达到5MB或更大
  3. 数据有效期不同:
类型数据有效期
sessionStorage仅在当前浏览器窗口关闭前有效
localStorage始终有效,窗口或浏览器关闭也一直保保存,因此用作持久数据
cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
  1. 作用域不同:
类型作用域
sessionStorage不在不同的浏览器页面中共享,即使同一个页面
localStorage在所有同源页面窗口中都是共享的
cookie在所有同源页面窗口中都是共享的

49. transform、transition、translate、animation的区别

  • transitiontransformanimation这三个是CSS属性,而translate2D转换的一种方法,是transform的一个属性值
  • transform2D、3D变换的属性,只是动画可用的一种属性,因为使用transform不会引起页面的重排
  • transitionanimation才是动画中必备的两个属性

50. CSS画三角形

div {
        border-left:50px solid transparent;
        border-right:50px solid transparent;
        border-bottom:50px solid #333;
        width:0;
        height:0;
    }