前端面试笔记

前言

这里是关于前端面试的一些题,我整理了一些经常被问到的问题,出现频率比较高的问题,以及个人经历过的问题。如有不足之处,麻烦大家指出,持续更新中…(ps:一到三颗⭐代表重要性,⭐选择性了解,⭐⭐掌握,⭐⭐⭐前端需要知道的知识)
在这里插入图片描述
Enchanted

一、HTML篇

1.语义话的目的是什么?⭐

答:用正确的标签做正确的事。

提高代码的可读性,页面内容结构化,有利于开发和维护,同时提高的用户体验,有利于SEO。

2.HTML5新特征⭐⭐⭐

  • Canvas绘图以及SVG绘图。
  • 拖放(Drag and drop)API
  • 语义化标签(header、nav、footer、article、section)
  • 音频、视频(audio、video)API
  • 地理定位(Geolocation)
  • 本地离线存储(localStorage),长期存储数据,关闭浏览器后不丢失。
  • 会话储存(sessionStorage),数据在关闭浏览器后自动删除。
  • 表单控件(calendar、date、time、email、url、search)
  • 多任务 webworker
  • 全双工通信协议 websocket
  • 历史管理 history
  • 跨窗口通信 PostMessage
  • Form Data 对象

3.cookie与sessionStorage和localStorage的区别⭐⭐⭐

  1. 保存方式
    cookie存放在客户的浏览器上。
    session都在客户端中保存,不参与服务器通讯。

  2. 生命周期
    cookie可设置失效时间
    localStorage除非手动清除否则永久保存
    sessionStorage关闭当前页面或浏览器后失效

  3. 存储的大小
    cookie 4kb左右
    session 5M

  4. 易用性
    cookie需自己封装
    session可以接受原生接口

因为cookie每次请求都会携带在http请求中,所以它的主要用来识别用户登录,localStorage可以用来跨页面传参,sessionStorage可以用来保留一些临时数据。

关于storage使用的方式可以查看storage传值

二、CSS篇

1.css有哪些基本的选择器,执行先后顺序?⭐

类选择器(class)、标签选择器、ID选择器
!important>内联样式(非选择器)>ID选择器>类选择器>标签选择器>通配符选择器(*)

2.垂直居中DIV⭐⭐⭐

请看这里前端CSS布局问题

3.两栏布局左边固定右边自适应⭐⭐

请看这里前端CSS布局问题

3.三栏布局左右固定中自适应⭐⭐

请看这里前端CSS布局问题

4.常用的块与行属性内标签有哪些?有什么特征⭐⭐

块标签:div、h1~h6、ul、li、table、p、br、form。
特征:独占一行,换行显示,可以设置宽高,可以嵌套块和行
行标签:span、a、img、textarea、select、option、input。
特征:只有在行内显示,内容撑开宽、高,不可以设置宽、高(img、input、textarea等除外)。

5.清除浮动⭐⭐⭐

  1. 父级div定义overflow:hidden(如果父级元素有定位元素超出父级,超出部分会隐藏,)
  2. 给浮动元素父级增加标签(由于新增标签会造成不必要的渲染,不建议使用)
  3. 伪元素清除浮动:给浮动元素父级增加 .clearfix::after(content: ‘’; display: table; clear: both;)(不会新增标签,不会有其他影响,)

6.CSS3新特征⭐⭐⭐

  1. 圆角(border-radius)
  2. 阴影(box-shadow)
  3. 文字特效(text-shadow)
  4. 线性渐变(gradient)
  5. 变换(transform)
  6. 更多的CSS选择器
  7. 更多背景设置(background)
  8. 色彩模式(rgba)
  9. 伪元素(::selection)
  10. 媒体查询(@media)
  11. 多栏布局(column)
  12. 图片边框(border-image)

7.介绍一下盒模型⭐⭐

答:

  1. 盒模型由内容(content)、内边距(padding)、边框(border)、外边距(margin)组成。
  2. 盒模型分为IE盒模型和W3C标准盒模型。
  3. W3C标准盒模型又叫content-box,元素宽度/高度由border+padding+content组成。
    (属性width,height只包含内容content,不包含border和padding)
  4. IE盒模型又叫border-box,元素宽度/高度由content组成。
    (属性width,height包含border和padding,指的是content+padding+border。)

PS:盒模型这个东西需要多理解。。。

8.CSS中有哪些长度单位?⭐⭐

  1. 绝对长度单位:px
  2. 百分比: %
  3. 相对父元素字体大小单位: em
  4. 相对于根元素字体大小的单位: rem
  5. 相对于视口*宽度的百分比(100vw即视窗宽度的100%): vw
  6. 相对于视口*高度的百分比(100vh即视窗高度的100%): vh

9.display:none和visibility:hidden的区别⭐

display:none:隐藏元素,在文档布局中不在给它分配空间(从文档中移除),会引起回流(重排)。
visibility:hidden: 隐藏元素,但是在文档布局中仍保留原来的空间(还在文档中),不会引起回流(重绘)。

10. 用CSS 实现长宽为浏览器窗口一半的正方形⭐

  1. 已知父元素宽高用%
                width: 50%;
                padding-top: 50%;
                background-color: red;
  • 用vw
                width: 50vw;
                height: 50vh;
                background-color: red;

11. 用CSS 实现高度为0.5像素的线条⭐

这个可以用伪类来实现

       .line::before {
            display: block;
            content: "";
            height: 1px;
            left: -50%;
            position: absolute;
            background-color: #333333;
            width: 200%; //设置为插入元素的两倍宽高
            -webkit-transform: scale(0.5);
            transform: scale(0.5);
            box-sizing: border-box;
        }

12. 用CSS 实现三角形⭐

向上

                width:0;
                height:0;   
                border-left:30px solid transparent;   
                border-right:30px solid transparent;   
                border-bottom:30px solid red;

13. 伪类和伪元素的区别⭐⭐

伪类
在这里插入图片描述
伪元素
在这里插入图片描述
区别

  • 伪类只能使用“”,伪元素既可以使用“:”,也可以使用“::”
  • 伪元素其实相当于伪造了一个元素,伪类没有伪造元素,例如first-child只是给子元素添加样式而已。(本质区别就是是否抽象创造了新元素

13. 重绘和重排是什么?如何避免?⭐⭐

重排:当DOM的变化影响了元素的几何信息(元素的的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。
重绘:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,所以重绘跳过了创建布局树和分层的阶段。

重排需要重新计算布局树,重绘不需要,重排必定发生重绘,但是涉及到重绘不一定要重排 。涉及到重排对性能的消耗更多一些。

触发重排的方法: 页面初始渲染、添加/删除可见的DOM元素、改变元素位置、改变元素尺寸、改变元素内容、改变元素字体大小、改变浏览器窗口尺寸、设置 style 属性的值等。
避免重排的方式:样式集中改变、使用 absolute 或 fixed 脱离文档流。

14. flex⭐⭐⭐

详情可以看详细解析flex布局教程

15. 什么是BFC?

全称:Block Formatting Context(块级格式化上下文)
含义:独立的渲染区域,规定了在该区域中,常规流块盒的布局。
创建 BFC:

  • 根元素
  • 浮动元素(元素的 float 不是 none)
  • 绝对定位元素(元素的 position 为 absolute 或 fixed)
  • 行内块元素(元素的 display 为 inline-block)
  • overflow 不为 visible 的块级盒子

BFC 内部的元素布局不受外部影响,即使两个相邻的元素浮动,它们也不会重叠。但是,在同一个 BFC 中的两个元素之间可能会发生盒子重叠问题。
BFC 还具有很多其他特性,例如可以包含浮动元素,防止父元素高度塌陷。常用的解决外边距塌陷的方法也是通过创建 BFC 来实现。

三、JS篇

1.ES6新特性?⭐⭐⭐

  1. 新增块级作用域let定义变量和const定义常量 详情可以参考var、let、const的区别
  2. 变量的解构赋值
  3. 模板字符串 (‘${}’)
  4. 默认参数(key=value)
  5. 箭头函数(=>)
  6. 扩展运算符(…)
  7. 模块(import/export)
  8. 类(class/extends)
  9. Promise
  10. Proxy
  11. Symbol
    了解关于es6的更多知识可以看阮一峰——ES6 入门教程

2.闭包的理解⭐⭐

理解:主要是为了设计私有的方法和变量。
优点:可以避免全局变量造成污染。
缺点:闭包会常驻内存,增加内存使用量,使用不当会造成内存泄漏。
特征:(1)函数嵌套函数。(2)在函数内部可以引用外部的参数和变量。(3)参数和变量不会以垃圾回收机制回收。

3.call()、apply()、bind()的区别⭐

详情请看call()、apply()、bind()重新定义this的区别

4.原型,原型链⭐⭐⭐

主要是还是实现继承与扩展对象。
每个函数对象都有一个 prototype 属性,这个属性就是函数的原型对象。
原型链是JavaScript实现继承的重要方式,原型链的形成是真正是靠__proto__ 而非prototype。

所有的引用类型(包括数组,对象,函数)都有隐性原型属性(proto), 值也是一个普通的对象。
所有的引用类型的 proto 属性值都指向构造函数的 prototype 属性值。
构造函数 new 出来一个对象,而每个对象都有一个 constructor 属性,该属性指向创建该实例的构造函数。
实例对象通过__proto__或者 object.getPrototype 的方法获取原型。
原型链其实就是有限的实例对象和原型之间组成有限链,就是用来实现共享属性和继承的。
原型链:通过原型继承多个引用类型的属性和方法。
构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型有一个属性指回构造函数,而实例有一个内部指针指向原型。
详细可以看看这篇文章最详尽的 JS 原型与原型链终极详解

5.JS基本数据类型⭐⭐

  1. 基本数据类型
  • Number:数值,包括整型和浮点型。
  • String:字符型。
  • Undefined:未定义,声明变量时未赋值。
  • Null:定义为空或者不存在。
  • Boolean:布尔值,true or false。
  • Symbol:独一无二的值。
  1. 引用数据类型
  • Object:对象。
  • Array:数组。
  • Function:函数。

基本数据类型是直接存储中的简单数据段,占据空间小、大小固定,属于被频繁使用的数据。栈是存储基 本类型值和执行代码的空间。

引用数据类型存储内存中,占据空间大、大小不固定。引用数据类型在栈中存储了指针,该指针指向堆 中该实体的起始地址,当解释器寻找引用值时,会检索其在栈中的地址,取得地址后从堆中获得实体。

两种数据类型的区别:

  • 堆比栈空间大,栈比堆运行速度快。

  • 堆内存是无序存储,可以根据引用直接获取。

  • 基础数据类型比较稳定,而且相对来说占用的内存小。

  • 引用数据类型大小是动态的,而且是无限的。

    注: Object.prototype.toString.call() 适用于所有类型的判断检测

关于Object的方法可以看这个JS中Object方法大全

6.export和export default的区别⭐

  • 均可导出常量、函数、文件、模块等。
  • 在一个文件或模块中,export、import可以有多个。export default仅有一个。
  • 通过export方式导出,在导入时要加{ },export default则不需要。

7.箭头函数和普通函数的区别⭐⭐

  • 语法更加简洁、清晰,=>()
  • 箭头函数是匿名函数,不能作为构造函数,不能使用new
  • 箭头函数不能使用arguments,而用reat参数…解决
  • 箭头函数没有自己的this,会捕获其所在的上下文的this值,并且不能通过call()和apply()来改变其this
  • 箭头函数没有原型

8.GET和POST的区别⭐⭐⭐

表面区别

  • 后退/刷新:GET无害,POST数据会被重新提交。
  • 书签:GET产生的URL地址可以被收藏为书签,而POST不可以。
  • 数据:GET一般是用来获取数据,POST提交数据。
  • 数据类型:GET只允许ASCII字符,POST无限制。
  • 数据大小:GET大小有限制(一般来说1024字节),POST理论上来说没有大小限制。
  • 安全性:GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
  • 可见性:GET参数通过URL传递对所有人可见,POST数据不可见。
  • 历史保留:GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

9.forEach和map的区别⭐⭐

forEach没有返回值,不能链式调用。
map返回新的数组,可以链式调用其他方法。

map创建新数组(不会修改原来数组),forEach不修改原数组。

map:将原数组中的每个元素通过回调函数转换成一个新的元素,然后组成一个新的数组。
forEach将每个元素传递给指定的回调函数,并对每个元素执行特定的操作。

10.JS基本数据类型的比较⭐⭐

黄色表示ture

11.遍历方式for in、for of、forEach的区别⭐⭐

for…in 遍历对象的可枚举属性,包括对象原型链上的属性。它通过遍历对象的键来实现迭代,一般用于遍历对象属性。如果遍历数组则返回的是索引。
注意,使用 for…in 遍历时,还需要使用 hasOwnProperty() 方法来判断属性是否来自对象本身,并避免遍历原型链上的属性。

        let object = { a: 1, b: 2, c: 3 }
        let array = [1, 2, 3, 4, 5]
        for (const key in object) {
            console.log(key);     //a, b, c
        } for (const key in array) {
            console.log(key);     //0, 1, 2, 3, 4
        }

for…of 遍历支持迭代协议的数据结构(数组、字符串、Set、Map 等),而不包括对象。
它通过遍历可迭代的对象的值来实现迭代,一般用于遍历数组、集合等迭代器对象。

    let array = [1, 2, 3, 4, 5]
    for (const key of array) {
        console.log(key); //1, 2, 3, 4, 5
    }

forEach 需要传入一个回调函数,用于对每个元素进行操作。for…in 和 for…of不用。
forEach 不支持 break 和 return 语句跳出循环,如果需要跳出循环可以使用 some() 或 every() 方法。

12.简述一下你理解的面向对象⭐

面向对象是基于万物皆对象这个哲学观点. 把一个对象抽象成类,具体上就是把一个对象的静态特征和动态特征抽象成属性和方法,也就是把一类事物的算法和数据结构封装在一个类之中,程序就是多个对象和互相之间的通信组成的。

面向对象具有封装性,继承性,多态性

封装:隐藏实现细节,使得代码模块化;
继承:扩展已存在的代码模块(类),它们的目的都是为了——代码重用。
多态:相同的事物,调用其相同的方法,参数也相同时,但表现的行为却不同。多态分为两种,一种是行为多态与对象的多态

13. == 和 ===的区别⭐⭐

==!=:在比较前会进行强制类型转换,再确定操作符是否相等。
规则:

  • 如果是Boolean,将其转换为数值再比较是否相等,false转换为0,true转换为1
  • 如果是String,将其转换为数值
  • 如果是{},则调用对象的**valueOf()**取得其原始值,再比较
  • null == undefined
  • null和undefined不能转换为其他类型值再比较
  • 如果有一个操作数为NaN,则==返回false,!=返回true,NaN不等于NaN
  • 如果都是对象,则比较是不是同一个对象,如果都指向同一个对象,则返回true,否则false。

==只比较不比较类型
=== 会判断类型

 '1' === 1(false)     undefined === null(false)

14. 数组有哪些方法⭐⭐

详细可以看数组一些常用的方法

15. 普通的数组去重(笔试一般都会有)⭐⭐

在不涉及去重对象、NaN等情况下。

  1. IndexOf()
  2. 双重for循环
  3. […new Set()]
  4. filter()
  5. sort()

注 :如果有多维数组如 [1,[2],[3,[2,3,4,5]] ] 先扁平化再去重,
Array.flat(Infinity)实现扁平化。

16. Promise⭐⭐⭐

含义:异步编程的一种解决方案,它通过链式调用 then 、 catch 、finally方法来处理异步调用的结果。。
三种状态pending(进行中)、resolved (已成功)和reject(已失败) (Promise对象的状态改变,只有两种可能:从pending变为resolve和从pending变为reject。

const promise = new Promise(function(resolve, reject) {
  // ... some code
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

resolve:将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved)。
reject:将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected)。

Promise 可以通过链式调用的方式,让多个异步请求形成一个顺序执行的队列。

then: Promise 实例添加状态改变时的回调函数。
可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。
catch : 用于指定发生错误时的回调函数。
finally: 不管 Promise 对象最后状态如何,都会执行的操作。

其他方法
Promise.all():将多个 Promise 实例,包装成一个新的 Promise 实例。

缺点: 无法取消Promise,一旦新建它就会立即执行,无法中途取消。如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

更多详情请看Promise 对象

17.promise 和 async/await 的区别 ⭐

Promise 和 async/await 都是用于处理异步任务的方式

相同点:
Promiseasync/await 的目的都是处理异步任务。
Promiseasync/await 都可以避免回调地狱。

不同点:
处理异步调用的结果方法:
Promise 通过链式调用 then 方法和 catch 方法来处理异步调用的结果。
而 async/await 通过 await 关键字和 try…catch 语句来处理异步调用的结果。
异步处理方式
Promise 是一种基于回调函数的异步处理方式。
async/await 是一种基于生成器函数的异步处理方式。
创建Promise方法
Promise 可以直接使用静态方法 Promise.resolve() 和 Promise.reject() 来创建 Promise 对象。
async/await 则需要借助于 Promise 对象创建。
是否可以阻塞
Promise 是非阻塞的。
async/await 是可以阻塞执行的(注意:这里说的阻塞是指异步等待结束后再继续执行后续代码,但不会阻塞线程)。

18.JS中new操作符有什么用?⭐⭐

  • 创建临时对象,并将this指向临时对象
  • 将构造函数的原型属性方法挂载到新对象的__proto__(原型指针)上
  • return 临时对象

19.JS获取HTML DOM元素的方法⭐⭐

  • 通过ID获取(getElementById)
  • 通过name属性(getElementsByName)
  • 通过标签名(getElementsByTagName)
  • 通过类名(getElementsByClassName)
  • 获取html的方法(document.documentElement)
  • 获取body的方法(document.body)
  • 通过选择器获取一个元素(querySelector)
  • 通过选择器获取一组元素(querySelectorAll)
    用法以及防坑可看JS获取HTML DOM元素的方法

20.事件捕获和事件冒泡⭐⭐

  • 事件捕获和事件冒泡主要解决了页面事件流的问题。页面的事件流经过了三个阶段,分别是事件捕获、目标阶段和事件冒泡阶段。
  • 事件捕获是由外向内;而事件冒泡则是由内向外。
  • event.stopPropagation() 可以阻止事件流的进一步传播。
  • 采用事件代理的方式,能够节省内存消耗,对于动态改变子元素的时候,也非常有利,避免了很多麻烦的步骤,比如重新绑定事件。(把子元素的事件委托给父元素来处理)

21.虚拟dom⭐

定义:虚拟DOM就是普通的js对象。用来描述真实dom结构的js对象,因为它不是真实的dom,所以才叫做虚拟dom。
作用:虚拟dom可以很好地跟踪当前dom状态,因为它会根据当前数据生成一个描述当前dom结构的虚拟dom,然后数据发生变化时,有生成一个新的虚拟dom,而两个虚拟dom恰好保存了变化前后的状态。然后通过diff算法,计算出当前两个虚拟dom之间的差异,得出一个更好的替换方案。

22.数组操作方法会改变原数组⭐⭐

会改变:push(),pop(),shift(),unshift() ,splice(),sort(),reverse()。
不变:concat(),split(),slice()。

23.JS有几种方法判断变量的类型?⭐⭐⭐

  1. typeof
    判断基本数据类型,
typeof(null) 'object'   typeof(undefined) 'undefined'  typeof([]) 'object'   typeof({}) 'object'
typeof(0)  'number'     typeof('0') 'string'       typeof(true)  'boolean'   typeof(Symbol()) 'symbol'

对于引用数据类型除了function返回’function‘,其余全部返回’object’。
可以返回类型 number、string、boolean、undefined、object、function、symbol。
2. instanceof
区分引用数据类型,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true,不太适合用于简单数据类型的检测,检测过程繁琐且对于简单数据类型中的undefined, null, symbol检测不出来。
3. constructor
检测引用数据类型,检测方法是获取实例的构造函数判断和某个类是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰。
4. Object.prototype.toString.call()
适用于所有类型的判断检测,检测方法是Object.prototype.toString.call(数据) 返回的是该数据类型的字符串。(举例:字符串返回的是[object String])

instanceof的实现原理:验证当前类的原型prototype是否会出现在实例的原型链__proto__上,只要在它的原型链上,则结果都为true。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,找到返回true,未找到返回false。
Object.prototype.toString.call原理:Object.prototype.toString 表示一个返回对象类型的字符串,call()方法可以改变this的指向,那么把Object.prototype.toString()方法指向不同的数据类型上面,返回不同的结果

24.如何判断一个对象是否存在?⭐

直接!XXX 这样会报错,因为没有定义
在这里插入图片描述
建议使用typeof运算符,判断XXX是否有定义。
在这里插入图片描述

25.undefined和null 区别⭐

undefined:一个变量已经声明但未被赋值,或者一个对象属性不存在
null: 一个变量或对象属性被明确地赋值为 null,表示该变量或属性的值为空。
undefined 表示缺少值,而 null 表示有一个值,但这个值是空的。
type检测 null为object, undefined为undefined

以下场景会出现undefined

  • 声明了一个变量,但没有赋值
  • 访问对象上不存在的属性
  • 函数定义了形参,但没有传递实参
  • 使用 void 对表达式求值

26.break 和 return 的区别⭐

作用对象不同
break 用于跳出当前的循环或者 switch 语句。
return 用于结束当前函数并返回一个值。
结束方式不同
break 只是提前结束当前的循环或者 switch 语句,然后继续执行后续代码
return 则会直接结束函数的执行,并将一个指定的值返回给调用处。
使用场景不同
break 通常用于跳出不满足条件或者特定情况的循环结构,避免出现死循环。
return 主要用于结束函数执行,返回一个执行结果或者错误信息等。

三、计算网络与其他知识篇

1.HTTP与HTTPS⭐

HTTP:客户端与服务器之间数据传输的格式规范,表示“超文本传输协议”。
HTTPS:在HTTP与TCP之间添加的安全协议层。
默认端口号:HTTP:80,HTTPS:443。
传输方式:http是明文传输,https则是具有安全性的ssl加密传输协议。
连接方式:http的是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

2.TCP与UDP的区别⭐

  1. TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。
  2. TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
  3. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
  4. TCP首部开销20字节;UDP的首部开销小,只有8个字节。
  5. TCP提供可靠的服务。UDP适用于一次只传少量数据、对可靠要求不高的环境。

3.三次握手四次挥手⭐

原因:TCP是面向连接的,三次握手就是用来建立连接的,四次握手就是用来断开连接的。

关于三次握手先看草图(看图理解)
请添加图片描述

最开始客户端和服务端都处于关闭状态,客户端主动打开连接。
第一次握手:客户端向服务端发送SYN报文,并处于SYN_SENT状态。
第二次握手:服务端收到SYN后应答,并返回SYN+ACK报文,表示已收到,并处于SYN_RECEIVE状态。
第三次握手:客户端收到服务端报文后,再像服务端发送ACK包表示确认。此时双方进入ESTABLISHED状态。(这次报文可以携带数据

为什么不是两次握手
原因:是因为如果只有两次,在服务端收到SYN后,向客户端返回一个ACK确认就进入ESTABLISHED状态,万一这个请求中间遇到网络情况丢失而没有传给客户端,客户端一直是等待状态,后面服务端发送的信息客户端也接受不到了,所以要客户端再次确认。

关于四次挥手先看草图(看图理解)
请添加图片描述
最开始客户端和服务端都处于ESTABLISHED状态,客户端主动关闭连接。
第一次挥手:客户端准备关闭连接,向服务端发送一个FIN报文,进入FIN_WAIT1状态。
第二次挥手:服务端收到后,向客户端发送ACK确认报文,进入CLOSE_WAIT状态,
第三次挥手:客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。等待服务端处理完数据后,向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。
第四次挥手:客户端收到FIN+ACK包后,再向服务端发送ACK包,
等待两个周期后再关闭连接。服务器收到了 ACK 应答报文后,关闭连接。

客户端在要等2周期再关闭
为的是确认服务器端是否收到客户端发出的 ACK 确认报文,当客户端发出最后的 ACK 确认报文时,并不能确定服务器端能够收到该段报文。服务端在没收收到ACK报文之前,会不停的重复发送FIN包而不关闭,所以得等待两个周期。

4.HTTP常见的状态码⭐

HTTP常见的状态码

5.如何解决跨域⭐⭐⭐

什么是跨域?
跨域是因为浏览器的同源策略(Same Origin Policy)限制导致的。
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域
常见的:
1、JSONP跨域
JSONP 可以跨域传递数据,基本原理是通过前端动态创建一个 <script> 标签,其中的 src 属性指向一个跨域 API 的 URL,该 URL 带有一个参数 callback,跨域 API 返回一段特定格式的 JavaScript 代码,其中 callback 函数的参数就是前端传回去的数据,前端获得结果后可以在本地执行回调函数。

2、跨域资源共享(CORS)
服务器端设置 HTTP 响应头部,使得浏览器可以跨域访问,服务器返回的响应头中包含 Access-Control-Allow-Origin 字段,指定可访问该资源的域名白名单,浏览器在接收响应时自动识别该字段判断该响应是否可跨域访问。

3、代理跨域 API 请求
使用自己的后端服务器作为代理服务器,把 API 请求发给服务器,服务器将请求转发到目标域名 API 并从服务器返回数据给前端,此时,前端 AJAX 请求的就是同域的 API,不存在跨域请求的问题了。

4、WebSocket协议跨域
基于 WebSocket 协议进行实时双向数据传输,但是需要服务端和客户端同时支持该技术。WebSocket 允许跨域使用。
5、proxy
前端配置一个代理服务器(proxy)代替浏览器去发送请求:因为服务器与服务器之间是可以通信的不受同源策略的影响。
所有的请求都发送到同一个本地后端 API,后端服务器再将请求转发到真正的目标域名服务器上。

6.网页从输入url到页面加载发生了什么⭐⭐

  1. DNS解析
  2. TCP连接
  3. 发送HTTP请求
  4. 服务器处理请求并返回HTTP报文
  5. 浏览器解析并渲染页面————>1.解析文档构建dom树。2.构建渲染树。3.布局与绘制渲染树。
  6. 连接结束

7.HTTP 传输过程⭐

含义:从建立连接到断开连接一共七个步骤,就是三次握手四次挥手

  1. TCP 建立连接
  2. 浏览器发送请求命令
  3. 浏览器发送请求头
  4. 服务器应答
  5. 服务器回应信息
  6. 服务器发送数据
  7. 断开TCP连接

8.浏览器如何渲染页面的?⭐

  1. 浏览器解析html源码,将HTML转换成dom树,
  2. 将CSS样式转换成stylesheet(CSS规则树),
  3. 浏览器会将CSS规则树附着在DOM树上,并结合两者生成渲染树(Render Tree)
  4. 生成布局(flow),浏览器通过解析计算出每一个渲染树节点的位置和大小,在屏幕上画出渲染树的所有节点
  5. 合成绘制生成页面。

9.对MVC和MVVM的理解⭐

M:model(数据模型),V:view(视图),C:controller(逻辑处理),VM:(连接model和view)
MVC:单向通信。必须通过controller来承上启下。
MVVM:数据双向绑定,数据改变视图,视图改变数据。

10.深拷贝,浅拷贝⭐⭐⭐

浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

深拷贝:将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。

总而言之,浅拷贝改动拷贝的数组原数组也会变(慎用!项目中很多地方共用的数组都会变)。深拷贝修改新数组不会改到原数组。
实现方法
浅拷贝

  1. Object.assign()
  2. 函数库lodash的 _.clone 方法
  3. es6的扩展运算符 (只能浅拷贝数组或对象中的引用类型的元素)
  4. Array.prototype.concat()
  5. Array.prototype.slice()
            let arr=[{name:"uzi"}]
 1.             let arr1= Object.assign({}, arr);   arr1[0].name="xiaoming"
 2.             let arr2= _.clone(arr);              arr2[0].name="mlxg"
 3.             let arr4 = arr.concat()              arr4[0].name="zitai"
 4.             let arr5 = arr.slice();              arr5[0].name="clearLove"
               console.log(arr[0].name==arr[1].name==arr[2].name==……);
               //true  arr[0].name="clearLove"

深拷贝

  1. JSON.parse(JSON.stringify())
  2. 函数库lodash的 _.cloneDeep 方法
  3. **jQuery.extend()**方法
  4. 手写递归方法(转)
  5. 扩展运算符…(只是一层的数组或者对象)
var $ = require('jquery'); 
            let arr=[{name:"theShy",age:"21"}]
 1.             let arr1= JSON.parse(JSON.stringify(arr));   arr1[0].name="rookie"
 2.             let arr2= _.cloneDeep(arr);                  arr2[0].name="ning"
 3.             let arr3= $.extend(true, {}, arr);           arr3[0].name="baolan"
                console.log(arr[0].name==arr[1].name==arr[2].name==……);
               //fales arr1[0].name="rookie" arr2[0].name="ning"

JSON.parse(JSON.stringify())使用限制:
该方法无法复制函数、正则表达式等非 JSON 数据类型。
对象属性的顺序会发生变化。
该方法无法处理循环引用的情况。

下面是一个简单的手写递归方法

function deepCopy(obj) {
  if (typeof obj !== "object" || obj === null) {
    return obj;
  }

  let newObj = Array.isArray(obj) ? [] : {};

  for (let key in obj) {
    newObj[key] = deepCopy(obj[key]);
  }

  return newObj;
}

对于扩展运算符的深拷贝和浅拷贝不同情况可以看数组一些常用的方法

11.防抖与节流⭐⭐⭐

防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间(多次执行变为最后一次执行
应用场景:
提交按钮用户注册时候的手机号验证邮箱验证

节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率(多次执行变成每隔一段时间执行
应用场景:
window对象的resize、scroll事件
拖拽时候的mousemove
射击游戏中的mousedown、keydown事件
文字输入、自动完成的keyup事件

vue中使用详情可以看vue中使用防抖和节流

12.性能优化⭐⭐

前端性能优化手段从以下几个方面入手:加载优化、执行优化、渲染优化、样式优化、脚本优化

  • 加载优化:减少HTTP请求、缓存资源、压缩代码、无阻塞、首屏加载、按需加载、预加载、压缩图像、减少Cookie、避免重定向、异步加载第三方资源

  • 执行优化:CSS写在头部,JS写在尾部并异步、避免img、iframe等的src为空、尽量避免重置图像大小、图像尽量避免使用DataURL

  • 渲染优化:设置viewport、减少DOM节点、优化动画、优化高频事件、GPU加速

  • 样式优化:避免在HTML中书写style、避免CSS表达式、移除CSS空规则、正确使用display:display、不滥用float等

  • 脚本优化:减少重绘和回流、缓存DOM选择与计算、缓存.length的值、尽量使用事件代理、尽量使用id选择器、touch事件优化

13.webpack是怎么打包的,babel又是什么⭐

Webpack:把所有依赖打包成一个 bundle.js文件,通过代码分割成单元片段并按需加载。Webpack是以公共JS的形式来书写脚本的,但对AMD/CMD的支持也很全面,方便旧项目进行代码迁移。
把项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。

babel将es6、es7、es8等语法转换成浏览器可识别的es5或es3语法。

14.git 和 svn的区别⭐

SVN集中式版本控制系统,版本库是集中放在中央服务器的,首先要从中央服务器哪里得到最新的版本,干完活后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作(如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就纳闷了)

Git分布式版本控制系统,没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,只需把各自的修改推送给对方,就可以互相看到对方的修改了。

15.vite和webpack的区别⭐⭐

  • 构建速度
    Vite 通过 ES Module 原生支持和开箱即用的特性,可以快速实现客户端和服务端的热更新,开发时的启动速度快,在初次构建和增量构建时性能均优于 Webpack。
    Webpack 需要通过分析所有的模块之后进行构建,而 Vite 利用浏览器支持的 ESM 原生支持的特性,通过直接加载文件来进行编译和构建,速度较 Webpack 更快。

  • 打包方式
    Vite 支持基于 ES Module 的原生打包,可以直接使用浏览器原生支持的 ES Module 特性进行代码打包和分发。
    Webpack 对开发者使用的方式相对更为多样化,例如支持 CommonJS、AMD 等 JavaScript 模块系统,更加灵活。

  • 插件生态
    相比于 ViteWebpack 社区相对更成熟和庞大,拥有更多的第三方插件和工具支持,可以满足更为复杂的打包需求。

  • 应用场景
    Vite 仅支持现代浏览器,因此仅适用于现代浏览器、轻量级应用场景和小型项目。
    Webpack 支持更为广泛,适用于大型项目和复杂应用场景。

总结:Vite 在性能和速度方面上优于 Webpack,特别是在开发环境下。
如果较大的项目,建议使用 Webpack 进行管理和构建。
当项目较小,且需要快速启动和热更新时,可以使用 Vite 来开发项目,更加高效。

16.require和import区别⭐⭐

  • 调用时间
    require 运行时 调用,理论上可以运用在代码任何地,甚至不需要赋值给某个变量之后再使用。
    lmport是 编译时 调用,必须放在文件开头,而且使用格式也是确定的。
  • 遵循规范
    require 是 AMD规范引入方式
    import是es6的一个语法标准,如果要兼容浏览器的话必须转化成es5的语法
  • 本质
    require是赋值过程,其实require 的结果就是对象、数字、字符串、函数等,再把require的结果赋值给某个变量。
    import是解构过程

通过require 引入基础数据类型时,属于复制该变量。
通过require 引入复杂数据类型时,数据浅拷贝该对象。
出现模块之间的循环引用时,会输出已经执行的模块,而未执行的模块不输出(比较复杂)。CommonJS模块默认export的是一个对象,即使导出的是基础数据类型。

ES6 模块语法是 JavaScript 模块的标准写法,坚持使用这种写法,取代 Node.js 的 CommonJS 语法。
使用import取代require()。

// CommonJS 的写法
const moduleA = require('moduleA');
const func1 = moduleA.func1;
const func2 = moduleA.func2;
// ES6 的写法
import { func1, func2 } from 'moduleA';

使用export取代module.exports。

// commonJS 的写法
var React = require('react');
var Breadcrumbs = React.createClass({
  render() {
    return <nav />;
  }
});
module.exports = Breadcrumbs;

// ES6 的写法
import React from 'react';
class Breadcrumbs extends React.Component {
  render() {
    return <nav />;
  }
};
export default Breadcrumbs;

17.事件循环(Event Loop)⭐⭐⭐

原因:JavaScript是单线程,所有任务需要排队,前一个任务结束,才会执行后一个任务。

所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。
同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务:不进入主线程、而进入"任务队列"的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

同步和异步任务分别进入不同的执行环境, 先执行同步任务,把异步任务放入循环队列当中挂起,等待同步任务执行完,再执行队列中的异步任务。异步任务先执行微观任务,再执行宏观任务。一直这样循环,反复执行。

微任务:Promise.then、catch、finally、async/await。
宏任务:整体代码 Script、UI 渲染、setTimeout、setInterval、Dom事件、ajax事件。

如果使用同步的方式,有可能造成主线程阻塞,从而导致消息队列中很多其他任务无法执行。这样一来,一方面会导致主线程白白浪费时间,另一方面导致页面无法及时更新,给用户造成卡死。
所以浏览器采用异步的方式来避免,从最大限度的保证了单线程的流畅运行。

18.什么是单页面应用(SPA)⭐

一个系统只加载一次资源,之后的操作交互、数据交互是通过路由、ajax来进行,页面并没有刷新。
在一个页面上集成多种功能,甚至整个系统就只有一个页面,所有的业务功能都是它的子模块,通过特定的方式挂接到主界面上。
优点

  • 前后端分离
  • 良好的交互体验——用户不用刷新页面,页面显示流畅
  • 减轻服务器压力——服务器只出数据
  • 共用一套后端代码——多个客户端可共用一套后端代码
  • 加载速度快,内容的改变不需要重新加载整个页面,对服务器压力小

缺点

  • SEO难度高——数据渲染在前端进行
  • 页面初次加载比较慢,页面复杂提高很多

多页面:一个应用多个页面,页面跳转时整个页面都刷新,每次都请求一个新的页面
优点:SEO效果好
缺点:页面切换慢,每次切换页面需要选择性的重新加载公共资源

详情可以参考构建单页Web应用

19.什么叫优雅降级和渐进增强?⭐

渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。
优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。

在传统软件开发中,经常会提到向上兼容和向下兼容的概念。渐进增强相当于向上兼容,而优雅降级相当于向下兼容。向下兼容指的是高版本支持低版本的或者说后期开发的版本支持和兼容早期开发的版本,向上兼容的很少。大多数软件都是向下兼容的。

二者区别:
1、优雅降级和渐进增强只是看待同种事物的两种观点。
2、优雅降级观点认为应该针对那些最高级、最完善的浏览器来设计网站。
3、渐进增强观点则认为应关注于内容本身。

19.浏览器内存泄漏?⭐⭐

概念:程序中己动态分配的堆内存由于某种原因未释放或无法被浏览器所回收,造成系统内存占用越来越大,最终导致程序运行缓慢甚至系统崩溃等严重后果。
原因:

  • 滥用全局变量,使这个变量一直留在内存中无法被回收
  • 不合理的使用闭包,从而导致某些变量一直被留在内存当中。
  • 没有清除定时器。
  • 未被销毁的事件监听。
  • 某些DOM操作(使用Dom对象绑定事件时,Dom对象消失后,还保留着没有及删除)。

20. iframe的优点、缺点⭐

优点:

  • iframe能够原封不动的把嵌入的网页展现出来。
    如果有多个网页引用iframe,那么你只需要修改iframe的内容,就可以实现调用的每一个页面内容的更改,方便快捷。
  • 网页如果为了统一风格,头部和版本都是一样的,就可以写成一个页面,用iframe来嵌套,可以增加代码的可重用。
  • 如果遇到加载缓慢的第三方内容如图标和广告,这些问题可以由iframe来解决。

缺点:

  • iframe会阻塞主页面的onload事件;
  • iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载。会产生很多页面,不容易管理。
  • iframe框架结构有时会让人感到迷惑,如果框架个数多的话,可能会出现上下、左右滚动条,会分散访问者的注意力,用户体验度差。
  • 代码复杂,无法被一些搜索引擎索引到,iframe会不利于搜索引擎优化(SEO)。
  • 很多的移动设备无法完全显示框架,设备兼容性差。
  • iframe框架页面会增加服务器的http请求,对于大型网站是不可取的。

21.排序方式⭐

  1. 冒泡排序:比较所有相邻元素,如果第一个比第二个大,则交换它们。(复杂度 O(n^2))
  2. 选择排序:找到数组中的最小值,选中它并将其放置在第一位。(复杂度 O(n^2))
  3. 插入排序:从第二个数开始往前比,比它大就往后排。(复杂度 O(n^2))
  4. 归并排序:把数组劈成两半,再递归地对数组进行“分”操作,直到分成一个个单独的数。(复杂度 O(nlog(n)))
  5. 快速排序:从数组中任意选择一个基准,所有比基准小的元素放到基准前面,比基准大的元素放到基准的后面。(复杂度 O(nlog(n)))
  6. 计数排序:使用一个用来存储每个元素在原始数组中出现次数的临时数组。在所有元素都计数完成后,临时数组已排好并可迭代以构建排序后的数组。(复杂度 O(n+k))
  7. 桶排序:将元素分为不同的桶(较小的数组),再使用简单的排序来对每个桶进行排序,然后将每个桶合并为数组。(复杂度 O(n))
  8. 基数排序:根据数字的有效位或基数将整数分布到桶中。基数是基于数组中的记数制。 (复杂度 O(n))在这里插入图片描述

四、TS篇

1.TS相比JS的有哪些优点⭐

支持静态类型定义提高了代码的可维护性和可读性,减少了代码错误。

2.TS的类型 ⭐⭐⭐

原始类型(Primitive Types)

  • boolean(布尔类型):true 或 false。
  • number(数值类型):整数或浮点数。
  • string(字符串类型):字符串值。
  • null(空类型):null 值。
  • undefined(未定义类型):undefined 值。
  • symbol(符号类型):唯一且不可变的值。

对象类型(Object Types)

  • object(对象类型):表示非原始类型即除了 number、string、boolean、symbol、null 或 undefined 以外的类型。
  • Array(数组类型):以特定顺序排列的数据,可以通过索引进行访问。
  • Tuple(元组类型):表示具有有限数量的未命名属性的数组,即允许不同类型的元素集合。
  • Function(函数类型):表示函数的类型。
  • Class(类类型):表示类的类型。

其它类型

  • unknown:表示任何类型,但在使用前必须先设法验证类型。
  • any:表示任意类型。
  • void:用于表示没有任何返回值的函数的类型。
  • never:表示不存在的类型值,通常用于表示永远不会抛出异常或永远不会有返回值的函数的类型。

3. type和interface的区别 ⭐⭐⭐

相同点:都可以给对象指定类型

区别:
interface:

  • 只能为对象指定类型
  • 可以使用extends继承
  • 多个同名的interface会合并

type:

  • 不仅可以为对象指定类型,实际上可以为任意类型指定别名
  • 可以使用&运算符实现继承效果
  • 多个同名的type会报错
  • type 可以声明基本类型别名,联合类型,元组等类型

五、VUE篇

关于vue的面试题移步这篇文章
前端面试题 — — vue篇

六、REACT篇

1.React的生命周期(版本17.0.2)⭐⭐⭐

概念:每个组件都包含 “生命周期方法”,你可以重写这些方法,以便于在运行过程中特定的阶段执行这些方法。
挂载

  • constructor():在 React 组件挂载之前,会调用它的构造函数。(注:如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。)
  • render(): class 组件中唯一必须实现的方法。
  • componentDidMount():在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。

更新

  • render(): class 组件中唯一必须实现的方法。
  • componentDidUpdate():在更新后会被立即调用。首次渲染不会执行此方法。

卸载

  • componentWillUnmount():在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。

具体可用一张图来表示
在这里插入图片描述

详情可看官网组件的生命周期

2.React如何获取组件对应的DOM元素?⭐⭐

  • ref:通过当前class组件实例的一些特定属性来直接获取子节点实例。
    注意:不能在函数组件上使用 ref 属性,因为他们没有实例。
  • findDOMNode():findDOMNode 是一个访问底层 DOM 节点的应急方案(escape hatch)。
    注意:在大多数情况下,不推荐使用该方法,因为它会破坏组件的抽象结构。严格模式下该方法已弃用。findDOMNode 不能用于函数组件。
    详情请看官网:ReactDOM

3.React中可以在render访问refs吗?为什么?⭐⭐

答:不能,因为在render阶段refs还未生成。DOM 的读取在 pre-commit 阶段,DOM的使用在 commit 阶段。
在这里插入图片描述

4.React中什么是受控组件和非控组件?⭐⭐

渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

受控组件更新state的流程:

  • 可以通过初始state中设置表单的默认值

  • 每当表单的值发生变化时,调用onChange事件处理器

  • 事件处理器通过事件对象e拿到改变后的状态,并更新组件的state

  • 一旦通过setState方法更新state,就会触发视图的重新渲染,完成表单组件的更新

对于受控组件来说,输入的值始终由 React 的 state 驱动。你也可以将 value 传递给其他 UI 元素,或者通过其他事件处理函数重置,但这意味着你需要编写更多的代码。
详情看官网受控组件

非受控组件
如果一个表单组件没有value props(单选和复选按钮对应的是checked props)时,就可以称为非受控组件。在非受控组件中,可以使用一个ref来从DOM获得表单值。而不是为每个状态更新编写一个事件处理程序。

官网解释:要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以 使用 ref 来从 DOM 节点中获取表单数据。

因为非受控组件将真实数据储存在 DOM 节点中,所以在使用非受控组件时,有时候反而更容易同时集成 React 和非 React 代码。如果你不介意代码美观性,并且希望快速编写代码,使用非受控组件往往可以减少你的代码量。否则,你应该使用受控组件。
官网非受控组件

总结: 页面中所有输入类的DOM如果是现用现取的称为非受控组件,而通过setState将输入的值维护到了state中,需要时再从state中取出,这里的数据就受到了state的控制,称为受控组件

5.谈一谈React的状态提升?⭐⭐

官网是这么解释的:

多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。

简单来说就是:将多个组件需要共享的状态提升到它们最近的父组件上,在父组件上改变这个状态然后通过props分发给子组件。对子组件操作,子组件不改变自己的状态。
可看官网的温度计数器例子

6.为什么要使用虚拟DOM?(什么是 Virtual DOM?)⭐⭐

Virtual DOM算法
用一张图片来表示
在这里插入图片描述
虚拟DOM
那就是虚拟DOM概念出现的地方,并且其性能要比真实DOM好得多。虚拟DOM只是DOM的虚拟表示。每当我们的应用程序状态更改时,虚拟DOM就会更新,而不是真实DOM。

React如何使用虚拟DOM

在React中,每个UI块都是一个组件,每个组件都有一个状态。React遵循可观察的模式,并监听状态变化。当组件的状态改变时,React更新虚拟DOM树。虚拟DOM更新后,React然后将虚拟DOM的当前版本与虚拟DOM的先前版本进行比较。此过程称为“差异化”。

一旦React知道哪些虚拟DOM对象已更改,然后React就会在真实DOM中仅 更新那些对象。与直接操作真实DOM相比,这使性能好得多。

原因:对于局部的小视图的更新,重新构造整棵 DOM没问题;但是对于大型视图,如全局应用状态变更的时候,需要更新页面较多局部视图的时候,这样的做法不可取。 Virtual DOM只是加了一些特别的步骤来避免了整棵 DOM 树变更。

简而言之就是:

  • 频繁的DOM操作昂贵且性能沉重。
  • 虚拟DOM是真实DOM的虚拟表示。
  • React使用虚拟DOM来增强其性能。
  • JS 和 DOM 之间的缓存。

更深入可看深度剖析:如何实现一个 Virtual DOM 算法

七、其它篇

1.谈项目⭐⭐⭐

2.项目开发中遇到的bug?⭐⭐

项目中或者地图中遇到引入如图片不显示。

解决办法:使用require动态引入图片。
详细可看设置content加载不出图标

合并多个对象并去重

原因:普通去重不能去除对象。
解决方法:可看数组中有对象去除

移动端1px问题

原因:手机分辨率高,它的实际物理像素数更多了,不同手机屏幕分辨率不同,一般都差不多2倍左右,所以显得更粗。
解决方法:可以参考第二篇CSS的11题。

移动端点击穿透问题

原因

  • 点击蒙层上的关闭按钮,蒙层消失后触发了按钮下面元素的click事件
  • 如果按钮下面恰好是一个有href属性的a标签,那么页面就会发生跳转
  • 这次没有蒙层,直接点击页内按钮跳转至新页,然后发现新页面中对应位置元素的click事件被触发了.
    解决方法
    最优解决方法——只用touch
    最简单的解决方案,完美解决点击穿透问题
    把页面内所有click全部换成touch事件( touchstart、touchmove、touchend)

项目中遇到bug总结:

基本上都是遇到一些样式的Bug,逻辑上的想想就解决了,没什么难的。

3.说说你在项目中遇到印象最深,最困难的地方,是怎么解决的?⭐⭐

(待补充)

4.你觉得你们项目还有哪些不足的地方?⭐⭐

(待补充)

5.工作之余你会做什么,看什么书?⭐

6.近几年的职业规划?⭐⭐

(待补充)

后言

其他hr常问的问题可以看这

前端面试hr经常会问的问题

总结

每天多学习一点,更进步一点
祝:大家早日找到理想的工作~
码字不易,持续更新中…

哪里有不足之处,麻烦指出,谢谢~~
请添加图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐