前言
本人也是大三到大四了,想在暑假找到一份工作。面了一些公司,汇总了一些面试常考题。因为答案都是基于个人来写所以可能并不是绝对正确,但是作者保证真的很用心去翻阅文档还有资料了。如果有错误欢迎评论区指正。我好好进行一个学习,谢谢大家了- ̗̀(๑ᵔ⌔ᵔ๑)
面试题
1-Node.js作为一种基于Chrome V8引擎的JavaScript运行环境,具有以下优势:
跨平台运行:Node.js能在多种操作系统上运行,如Windows、Linux和Mac OS X,便于开发跨平台应用程序。
单线程事件驱动架构:Node.js使用单线程事件驱动架构,能有效处理大量并发连接,适合构建实时应用,如即时聊天服务。
异步非阻塞I/O模型:这种模型允许Node.js在处理I/O操作时不会阻塞主线程,显著提高应用程序的性能和响应能力,尤其适用于处理高并发请求。
丰富的第三方模块:Node.js拥有庞大的第三方模块生态系统,便于开发者快速构建功能强大的应用程序。
简单易学的语法:基于JavaScript,其语法简单,易于上手,有利于快速开发。
广泛的社区支持:活跃的社区提供了丰富的资源和支持,便于解决问题和优化应用程序。
高性能和轻量级:Node.js在相对较低的硬件资源上即可运行,适用于云计算和分布式系统。
统一的语言开发:前后端均使用JavaScript,降低了开发成本,提高了开发效率。
2-项目发布的流程
测试:执行单元测试、集成测试和端到端测试,确保新的更改没有破坏现有功能。 打包:webpack,vite 进行一个项目的打包 预发布: 在预发布环境中部署,模拟生产环境进行最后的测试。 可以进行A/B测试或金丝雀发布,逐步放量。 部署: 使用持续集成/持续部署(CI/CD)工具(如Jenkins、GitLab CI/CD、Travis CI等)自动化部署流程。 部署到生产服务器,可以选择蓝绿部署、滚动更新等方式减少停机时间。
3-express和koa的区别
请记住,开发 Express 和 Koa 的是同一拨开发人员。Koa 只是 Express 的一个更轻量级的版本,
没有内置提供路由和模板引擎等功能。相比于 Koa,Express 更加成熟。
它的社区更为稳定,并且你可以在 Express 上找到比 Koa 更多的文档和示例。
虽然使用 Koa 可以使编写中间件更加简洁,但是使用 Express 结合 async
/await
也可以避免“回调地狱”并实现类似的语法。
总之,就是 Express 和 Koa 能够实现完全一样的功能。从性能来说轻量级的Koa对于我的项目来说性能会更好。
中间件处理:
Express:Express使用传统的中间件模式,其中中间件函数按顺序执行,每个中间件可以控制请求的流程,例如是否调用next()
。
Koa:Koa引入了“洋葱模型”中间件,它允许中间件以更灵活的方式处理请求和响应,可以在流程的不同阶段插入逻辑。
上下文(Context):
Express:Express使用传统的req
(请求)和res
(响应)对象。
Koa:Koa引入了ctx
(上下文)对象,它包含了req
和res
对象的封装,以及一些额外的功能。
异步处理:
Express:Express原生不支持异步中间件,通常需要使用回调或Promise来处理。
Koa:Koa内置了异步处理能力,它使用async/await语法,使得异步代码的编写更加直观和简洁。
4-node事件循环机制
这么通俗易懂的Node事件循环,背就完了 - 掘金 (juejin.cn)
5-vue2-vue3的区别
1. 语法区别
-
Vue 2:
- 主要使用选项式 API(Options API)。组件定义通过一个对象配置来完成,如
data
、methods
、computed
、watch
等属性都是在这个对象内定义的。 - 代码组织较为分散,相关联的数据和逻辑可能分布在不同的选项中,这可能会导致代码维护困难。
- 主要使用选项式 API(Options API)。组件定义通过一个对象配置来完成,如
-
Vue 3:
- 引入了组合式 API(Composition API),允许开发者在一个
setup()
函数中集中组织相关的状态和逻辑。 - 组合式 API 使得代码更加模块化和可复用,可以更容易地抽取和共享逻辑。
- 可以使用像
ref
、reactive
、computed
、watchEffect
和onMounted
这样的 Hooks 函数来替代 Vue 2 中的选项。 - vue3是全部使用TS进行编写,更加符合大型项目
- 引入了组合式 API(Composition API),允许开发者在一个
2. 响应式机制的改变
-
Vue 2:
- 使用
Object.defineProperty
来实现数据的响应式。当设置一个新属性时,需要手动调用$set
方法。 - 数组的变更检测存在局限性,例如直接修改数组的索引值或者添加/删除元素不会触发视图更新,需要使用特定的方法如
splice
或者$set
、push
等。
- 使用
-
Vue 3:
- 使用 Proxy 对象来代替
Object.defineProperty
,这提供了更全面的变更检测。 - Proxy 可以拦截更多的操作类型,包括但不限于属性的读取、写入、删除等,因此对于数组的操作可以自动捕获到变更。
- Vue 3 中的响应式对象还支持
readonly
和shallowReactive
等新的选项,提供更多灵活性。
- 使用 Proxy 对象来代替
3. Diff 算法的改进
-
Vue 2:
- 使用一种简单的 diff 算法,主要基于两个假设:元素的唯一标识(key)和同级元素的顺序。
- Vue 2 的 diff 算法相对简单,在复杂的应用场景下可能会导致不必要的重渲染。
-
Vue 3:
- 引入了更高效的 diff 算法,能够更好地处理复杂的 DOM 更新。
- Vue 3 的 diff 算法更加智能,能够在不破坏性能的前提下做出更精细的更新决策。
- Vue 3 的虚拟 DOM 实现也得到了优化,提高了渲染性能。
4.更加支持TypeScript
-
Vue 2:
- Vue 2 支持 TypeScript,但类型定义不是非常完善,使用 TypeScript 时可能遇到一些类型错误或警告。
-
Vue 3:
- Vue3 源码全面采用ts进行编写,组合式 API 的使用让 TypeScript 的类型推断变得更加容易,
- 提高了开发效率和代码质量。
5.vue3有一个frament进行包裹
Vue2必须拥有一个根元素,而Vue3使用fragment进行了一个包裹,减少不必要的DOM层级:这有助于简化DOM结构,减少内存使用,提高渲染效率。
6&7-文件上传,断点续传具体实现&文件上传进度
字节跳动面试官:请你实现一个大文件上传和断点续传 - 掘金 (juejin.cn)
8-大文件怎么实现分片上传
1.首先要拿到大文件的二进制数据
2.使用数组对大文件进行slice分割
3.使用Promise.all并发请求发送给后台(要保证数据传输的时候要携带当前是第几片)
- 传输完成后通知服务器进行合并
9-选择器的优先级
important! > 行内样式 > id选择器 > 类选择器 > 标签选择器 > 通配符选择器 > 浏览器代理样式(标签默认样式)
div~span 选择的是和div同一层级下面的所有span元素(注意:和div同一层级不是子元素的意思) --- 兄弟选择器
div+span 选择的是相邻兄弟选择器,div最近的下一个span元素,不能是上面的。
10-浮动是什么?怎么清除浮动?
浮动就是让元素脱离文档流,向左或者向右浮动,直到遇到另一个浮动元素
清除浮动的方法
- 在浮动元素的最后面添加一个块级空容器,在它身上clear:both;
- 在父容器的伪元素上做清除浮动
- 父元素设置为BFC容器 什么是BFC容器呢?
BFC容器全名叫做Block Formatting Context
1-主要有两个作用
1.1- bfc容器在计算高度会计算浮动元素的高度
1.2- bfc容器子元素的margin-top不会与父容器的margin-top重叠
2- 设置bfc的方法
2.1 display:flex,gird,inline-block,inline-table,inline-flex
2.2 overflow:hidden,scroll,auto
2.3 position:absolute,fixed
2.4 float:left,right
11-防抖截流
1- 什么是防抖截流
防抖就是在一段时间内只会执行最后一次的操作
截流是触发一段时间内,每段固定时间执行一次
2-原理和作用
防抖和截流都是使用了定时器进行一个计时
防抖就是判断是否计时器存在,存在就清除重新设置一个计时器,
这样就保证一段时间内只会触发最后一次。
截流就是判断计时器是否存在,存在就不执行,等到计时器执行执行之后,
才允许新的执行。
3-使用场景
一般都是用来进行一个性能优化,比如输入框一般就是使用防抖来进行一个
智能提示,而截流一般就是图片这种进行一个懒加载。
12-js,html,css是什么?
按照我的理解,应该从html来讲起。html是一个标记性语言,它主要是用来定义和展示页面的结构,
而css就孕育而生,它是用来给网页的结构和元素添加样式的,使得网页具有更好的观赏和交流性。
html+css的是静态网页,只能看但是没有功能。js的功能就来了,Js 可以用来控制网页的行为,
如响应用户的输入、操作DOM(文档对象模型)、它使网页变得动态和交互性强。
而微软提出的ajax更是让js更上一层楼,那就是它可以在不进行网页刷新的情况下进行网络通信。
这一特性使得 JavaScript 成为了非常热门的前端开发语言之一。
13-vue是什么?(和js对比的好处)
Vue.js 相对于原生 JavaScript(即纯 JavaScript)有许多优势,特别是在构建复杂的应用程序时。以下是 Vue.js 的一些主要优点:
1. 双向数据绑定
Vue.js 提供了双向数据绑定的能力,这意味着当模型(数据)发生变化时,视图(DOM)会自动更新;反之亦然。这大大简化了数据同步的过程,而使用原生 JavaScript 时,需要手动编写大量的代码来保持视图与数据的一致性。
2. 组件化
Vue.js 的一个关键特性是其强大的组件系统。组件可以被重用,这使得代码更加模块化和易于维护。每个组件都有自己的作用域和生命周期,这有助于隔离和管理不同部分的状态。
3. 易于学习和使用
Vue.js 的学习曲线相对较低,入门门槛不高。它提供了简洁的 API 和文档,使得开发者可以很快地上手并开始构建应用程序。
4. 渲染性能
Vue.js 使用虚拟 DOM(Virtual DOM)来提高渲染性能。它通过diff算法比较新旧虚拟 DOM 树来找出最小的变化集,并仅更新必要的部分,从而减少浏览器的重绘次数。
14-作用域
作用域是什么?
作用域是值得变量和函数生效的区域范围
有几种作用域?
一共有三种作用域,全局作用域,函数作用域,块级作用域。
块级作用域的形成是let,const和{}形成的,在块级作用域中是不能
在let和const变量声明前进行使用的,因为会造成暂时性死区。
15-组件通讯
组件的通讯,我一下记不太清一共有多少种了。我边讲。
1-defineProps,父给子传值
2-defineEmits,发布订阅机制,父组件订阅一个事件,子组件发布该事件
3-v-model,这是一个语法糖,类似于发布订阅,父组件将绑定的属性
传给子组件,订阅一个事件叫做update:xxx,子组件改动属性就会发布这个
事件,
4-Provide/Inject
5-pinia/vuex
16-Vue生命周期和钩子函数
vue3使用setup函数来移除了BeforeCreate和created钩子函数,
onBeforeMount
: 在组件挂载之前调用。onMounted
: 在组件挂载完成后立即调用。onBeforeUpdate
: 在组件更新之前调用。onUpdated
: 在组件更新完成后立即调用。onBeforeUnmount
: 在组件卸载之前调用。onUnmounted
: 在组件卸载之后立即调用。onActivated
: 如果组件是<KeepAlive>
缓存的一部分,则此钩子会在组件被激活时调用。onDeactivated
: 如果组件是<KeepAlive>
缓存的一部分,则此钩子会在组件被停用时调用。
17-react和vue的区别
我个人认为的react和vue的区别在于一下几点吧,
1.设计理念不同
react其设计理念是组件化开发。React主张使用JavaScript来处理更多的事情,推崇函数式编程,强调单向数据流,
设计模式是MVC模式,注重与MVC里面的V,也就是view层。react应用中数据对象是不可变的,需要使用setState方法更新状态;
而vue的话,设计理念是一个MVVM,用户只需要注重与M层的一个变化就可以了。因为vue底层就会帮我进行一个页面的更 新,页面的更新也会改动数据。
2.Diff算法的区别
React:React的diff算法称为Reconciliation,它通过比较虚拟DOM树来找出需要更新的部分。React的diff算法主要优化了树的遍 历,采用双端比较策略,提高了diff效率。
Vue:Vue的diff算法也借鉴了React的双端比较策略,但在此基础上进行了优化。Vue的diff算法在比较过程中会跳过静态节点,从而 提高渲染性能。
3.语法不同
React使用JSX语法,将HTML结构嵌入到JavaScript代码中,使得组件的结构和逻辑更加紧密。JSX需要通过Babel等工具转换成浏览器可识别的JS代码。
Vue:Vue使用模板语法,将HTML、CSS和JavaScript分离,更符合传统前端开发者的习惯。Vue的模板语法简洁明了,易于理解
18-this指向问题
this,apply,call,bind 超详细合集 - 掘金 (juejin.cn)
19-Promise
Promise是JavaScript中用于处理异步操作的一种对象,解决了回调地狱的问题,以下是Promise的五个关键点:
-
三种状态:
Promise对象有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。当Promise被创建时,它处于pending状态;当异步操作成功完成时,它变为fulfilled状态;如果异步操作失败,则变为rejected状态。
-
状态的不可逆性:
一旦Promise对象的状态从pending变为fulfilled或rejected,这个状态就不可再改变,即Promise对象的状态是永久性的。
-
链式调用:
Promise支持链式调用,这意味着可以在一个Promise完成后继续调用另一个Promise,从而形成一系列异步操作。这是通过在Promise上调用
.then()
方法实现的,它返回一个新的Promise。 -
错误捕获:
Promise提供了
.catch()
方法来捕获在执行过程中可能出现的错误。如果在Promise链中的任何地方发生错误,都可以被.catch()
捕获,从而避免程序崩溃,并允许开发者对错误进行处理。
我一般不怎么使用Promise,而是使用async和await,它们是语法糖本质还是Promise,但是写起来会更加简洁和语义化。但是它身上的一些静态方法我使用过。Promise.all,接受的是一个promise数组,只有当所有promise的状态变成了fulfilled的时候,它就会返回一个新的promise。我使用过它进行一个大文件分片的上传。用它来进行一个并发网络请求发送。
20-let 、var 和const的区别
let和const 与var有什么区别
let和const 是es6的新语法,在函数预编译的时候会进行变量提升,这样在变量还没有赋值的时候就可以进行访问。
但是let和const不会,而且let和const遇到{}会形成块级作用域,并且let和const在声明之前是不能访问的,也不能访问
外部具有相同名字的变量因为会形成暂时性死区。这就是let、const和var的区别。
let和const的区别
它们两个的区别主要在let是声明变量,而const是声明常量的。
21-说说类型判断
类型判断我一共知道以下几种
-
typeof
除了null以外的基本类型都能判断,null会被判定为object。对象只能判断出function()和object类型,其他引用类型统一为obejct类型
-
instanceof
可以判断的出,但是无法知道具体类型。
-
Object.prototype.toString()
可以知道具体类型,返回的是一个字符串"[object Object]"
-
Array.isArray()
只用来判断数组的
22-重排(回流)和重绘
html树+css树 = 渲染树
渲染树+布局 = 布局树
进行分层然后图层合成光栅化最后进行cpu渲染。
重排和重绘的概念
重排和重绘是浏览器渲染页面内容时,经历的一系列步骤,其中包括重排(Reflow)和重绘(Repaint)。
重排是指浏览器为了重新渲染部分或整个页面,需要重新计算元素的尺寸和位置。这就是设计到需要进行重新
构建布局树,等等一系列操作。比较消耗性能。
重绘是指浏览器更新元素的外观样式,但不改变布局。消耗的性能就很小。
什么会造成重排和重绘
重排的原因:元素节点的删除和增加,一些改变位置大小还有文档流的操作都会涉及到重排。
重绘的原因:一些修改元素的背景颜色,修改字体样式这些就不会触发重排,但是会进行重绘渲染。
DocumentFragment文档碎片,减少JS直接操作dom元素的style
----- 1万条数据如何渲染
- 文档碎片
- requestAnimationFrame比setTimeout更好
刷帧率
减少offsetWidth offsetHeight getBoundingClient等属性的调用,立马触发重绘重排
23-闭包
是什么
- 根据作用域的规则,内部函数总是可以访问外部函数中的变量,
又有当一个函数执行完毕之后函数的上下文一定会被销毁,那么为了同时
满足这两个规则,闭包这个概念就出现了。
当内部函数被拿到外部函数之外调用,即使外部函数执行完毕,它被
内部函数引用的部分会以一个集合的方式保存在调用栈中。改集合就叫闭包。
- 缺点: 容易内存泄露
- 优点:创建私有变量,不污染全局变量
- 应用场景:封装模块,
24-for in vs for of
for...in 循环
for...in
循环用于迭代对象的可枚举属性键。它可以用来遍历任何拥有属性的对象
- 遍历的是对象的所有可枚举属性键。
- 包括原型链上面的可枚举属性。
for...of循环
for...of
循环用于迭代可迭代对象(如数组、Set、Map 等)。
特点:
-
遍历的是可迭代对象的值。
-
适用于数组、Set、Map 等可迭代对象。
-
保证了遍历的顺序,对于数组来说是按照索引的升序。
普通对象无法使用因为它们是不可迭代的。
25-常用的数组遍历的方法
普通for循环,for of ,forEach ,map , reduce
26- 介绍一下jwt
jwt全面jsonwebToken,主要是用来进行一个安全的校验。前端在登录的时候向后端发送请求,
成功就会根据用户的信息还有私钥根据加密方式生产一串hash字符串也就是令牌,然后返回。之后的每次
请求都需要携带这个令牌给后端进行权限和安全的校验。
27-介绍一下富文本
富文本就是你可以输入一串文字,可以对文字进行一些样式的设计,比如加粗变大啊,图像、链接、表格都可以写,类似于md文档那种。
28-v-for 和key
15张图,20分钟吃透Diff算法核心原理,我说的!!! - 掘金 (juejin.cn)
vue里面v-for 为什么需要给每个元素添加一个key是为了高效的更新虚拟DOM,其实不只是 vue,react 中在执行列表渲染时也会要求给每个组件添加上 key 这个属性。
要讲清楚为什么可以高效更新虚拟DOM就必须了解Diff算法,Diff算法是一种对比算法。对比两者是旧虚拟DOM和新虚拟DOM
vue 和 react 的虚拟 DOM 的 Diff 算法,:
-
同一层级的一组节点,他们可以通过唯一的 id 进行区分。
-
当页面的数据发生变化时,Diff 算法只会比较同一层级的节点:
- 如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点以后的子节点了。
- 如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。
29-v-if,v-show
两者都可以进行一个元素的显示和隐藏,但是v-if进行元素隐藏是直接删除dom节点,而v-show是
display:none,一般如何你是想平繁动态切换就使用v-show,用完就不用的就用v-if.
30-路由守卫
路由守卫分为3大类,
- 全局守卫:它们会在每个路由变化时被调用,适用于所有路由。
- 路由独享守卫:只针对特定的路由进行调用。
- 组件内守卫:在组件内部定义,仅对该组件的路由变化有效。
-
全局守卫:
- beforeEach: 在每个路由改变之前执行的守卫。常用于权限检查、登录验证等。
- beforeResolve: 在路由解析前调用,用于拦截导航到同一路由的情况。
- afterEach: 每个路由改变后都会调用的守卫。通常用于在路由改变后进行一些操作,如修改标题、滚动位置等。
-
路由独享的守卫:
- beforeRouteEnter: 当进入一个路由时,在渲染该路由对应的组件之前被调用。
- beforeRouteUpdate: 当进入一个已经存在的路由时被调用,通常用于数据更新。
- beforeRouteLeave: 当离开一个路由时被调用,通常用于确认用户是否要离开当前页面,防止未保存的数据丢失。
一般路由守卫就是用来进行登录验证,权限控制。这两个功能我都使用和实现过。
登录验证就是判断用户是否进行过登录,然后一些非白名单的页面就进行校验,没有则跳转login登录页这样。
权限控制就是做后台管理系统的时候,进行过权限的控制。当时我是自定义了一个全局指令叫v-Permiss然后绑定需要
进行权限校验的元素,没有权限则隐藏该元素。
31-组件插槽
组件插槽的基本概念:
-
默认插槽(匿名插槽) :
- 在 Vue.js 中,如果你在组件的标签内部添加了一些内容,这些内容将会被传递到组件内部的一个默认插槽中。
- 在组件的模板部分,你可以使用
<slot>
标签来指定这些内容的渲染位置。
-
具名插槽:
- 当一个组件需要多个插槽时,你可以给每个插槽命名,这样你就可以控制内容在不同的位置渲染。
- 在父组件中使用
<template v-slot:slotName>
(简写为#slotName
)来指定内容应该被渲染到哪个具名插槽。
-
作用域插槽:
- 有时,插槽内容可能需要访问子组件的作用域内的数据。
- 在 Vue.js 中,你可以通过在
<slot>
标签上绑定属性来将子组件的数据传递给插槽。 - 父组件可以通过
<template v-slot:slotName="slotProps">
来接收这些数据,并在插槽内容中使用它们。
这些插槽我全部都使用过,具名插槽是我在手写vue-router的时候使用过用于指定渲染的插槽位置。
作用域插槽就是在对KeepAlive组件进行持久化都时候,在<router-view>
组件内部使用了一个作用域插槽,
并将当前路由匹配到的组件作为 Component
变量传递给插槽。也就是KeepAlive组件进行一个持久化。
32-vite和webpack
vite保留了esm的模块化这是浏览器原生支持的,让代码不像传统的构建工具一样需要去分析引入,打包构建,而是直接保持模块化,
webpack是commonJS浏览器读不懂,需要进行一个改变。
vite build是用go语言写的,多线程确实构建要比webpack块。
但是听说之前webpack的作者用rust底层写了一个叫做turbopack比vite更快
省去大量的编译时间,让代码更改后的响应速度大量提升。
一些浏览器是不认识import的(es6新语法)
可以在script标签中加入type="module"
代码压缩底层是使用的roll-up
热模块更新(HMR)是一种功能,允许在不重新加载整个页面的情况下,只更新页面上发生变化的模块。这意味着当你修改代码时,Vite 能够只重新编译和更新那些变化的模块,而不是整个应用,从而提供了更快、更流畅的开发体验。
- 本地开发的构建速度快,由于Vite是基于
ESM
和esbuild
的,所以在本地开发时整体的构建速度会比webpack
更快 - 使用简单,Vite内置了很多
loader
和配置,让开发者可以零配置跑起来一个项目,而webpack
则是需要写很多复杂的配置
33-Vite 中的热模块更新是如何工作的?
在 Vite 中,热模块更新是通过以下步骤实现的:
- 检测文件更改:Vite 监听项目文件系统的变化,比如打包的时候会使用到文件内容生成的hash值来检测文件是否更改。
- 编译更改的模块:一旦检测到文件更改,Vite 会重新编译受影响的模块。又因为Vite采用了esm的的模块化,所以无需更新其他模块内的代码。
以下是 Vite 中 HMR 的一些特点:
- 即时反馈:更改代码后,几乎立即就能看到页面上相应的更新,无需手动刷新页面。
- 保留应用状态:由于整个页面不需要重新加载,因此应用的状态(如变量状态、组件状态等)可以被保留。
- 高效的更新:只有更改的模块会被重新编译和更新,而不是整个应用。
- Vite本地启动时会创建一个
WebSocket
连接,同时去监听本地的文件变化 - 当用户修改了本地的文件时,
WebSocket
的服务端会拿到变化的文件的ID
或者其他标识,并推送给客户端 - 客户端获取到变化的文件信息之后,便去请求最新的文件并刷新页面
34-同源策略
同源策略本质是一种安全措施,用于限制一个网页的脚本与另一个来源的资源进行交互。这项政策旨在保护用户数据免受恶意脚本的攻击,防止数据泄露和其他安全风险。
1-JSONP
利用script标签不受同源策略的影响,需要服务器端的支持,将数据包裹在一个回调函数中返回。
2-设置Cors
服务器设置特定的 HTTP 请求头来实现,在请求头中加入Access-Control-Allow-Origin,可以让
浏览器对指定的请求源进行放行。服务器也可以设置一些设置比如指定允许的 HTTP 头部和请求方法。
3-服务器代理
浏览器的同源策略只会限制浏览器的网络请求,但是如果进行代码的话,那么就是服务器与服务器进行通信,然后设置的代理服务器和浏览器是同源的就不受同源策略的约束。
4-WebSocket
WebSocket 协议不受同源策略的限制,可以用来传输跨域数据
5-window.postMessage
可以在不同源的窗口之间传递消息。
35-数组去重
1-使用set进行数组去重,Array.from(new Set(arr));
2-数组排序后进行手动去重(双指针)
3-定义一个新数组通过includes和indexOf都可以进行去重
36-图片懒加载
是什么?
图片懒加载的原因是因为<img>
标签设置了src属性,浏览器就会自动去进行网络请求下载资源。
但是一个项目可能有很多图片,同时进行网络请求会减慢项目的启动速度。所以可以进行懒加载,
先对屏幕内的图片进行网络请求,在用户将会滚动到图片位置时,再发送请求加载图片。
怎么做?
我的项目中是使用了IntersectionObserver进行一个元素的观察,它是浏览器的一个原生API。可以
对元素进行观察,当元素进入观察的视口内就会触发回调函数,此时就可以进行一个图片url的设置,
浏览器将会自动进行网络请求。一个这个url的值存储在data-src中的。
这就是我对图片懒加载的理解。
37-数据基本类型和判断数据基本类型
基本数据类型:
number,string,boolean,null,undefined,bigint,symbol(新语法)
判断基本数据类型
type方法除了null之外都可以判断,instanceof是判断复杂数据类型,
要想详细判断基本数据类型和复杂数据类型需要使用Object原型上的toString方法
Object.prototype.toString.call();
38-div的隐藏方法
1.display:none; 无文档流 , 无法绑定点击事件
- opacity:0 有文档流, 可以触发点击事件
- width:0 height:0 无文档流,无法绑定点击事件
- visbility:hidden 无文档流,无法绑定点击事件
- clip-path: polygon(50px 50px, 100px 100px, 0 100px, 50px 50px);(三角形)有文档流,无法绑定事件
39-get和post的区别
-
GET 适合用于获取数据,且数据量不大,不包含敏感信息。
有长度限制一般是1-2kb根据浏览器而定,
get请求是将请求的一些数据用?拼接在url中,不安全,
-
POST 适合用于提交数据,比如登录、注册等,
对比GET来说POST的请求的数据在请求体中,相对更加私密和安全
-
GET 请求可以被浏览器缓存。
-
POST 请求不会被浏览器缓存。
根据restful准则 一切皆资源 统一的接口规范
GET 请求
POST 新增
PATCH/PUT 修S改
DELETE 删除
40-输入url后会发生什么
- 渲染页面
1. 渲染页面:
- 下载HTML:服务器响应请求,浏览器开始下载HTML内容。
- 构建DOM树:浏览器解析HTML标签,在内存中构建DOM树。
2. 处理CSS和渲染树:
- 下载CSS样式表:浏览器解析HTML中的`<link>`标签,下载CSS样式表。
- 构建CSSOM树:浏览器解析CSS文件,构建CSSOM(CSS Object Model)树。
- 构建渲染树:将DOM树和CSSOM树结合,构建渲染树(也称为布局树)。
3. 布局和绘制:
- 布局:浏览器计算每个节点的确切位置和大小,生成布局树。
- 绘制:浏览器将布局后的节点绘制到屏幕上。交给GPU渲染
4. JS是单线程 浏览器是多线程的
5. img link script ...浏览器会启动新的下载线程
6. 上高速 堵车
7. 有必要同时并发那么多图片
41-proxy和defineProperty的区别
Proxy
和 Object.defineProperty
都是 JavaScript 中用于操作对象属性的行为,但它们之间存在一些关键的区别。
Object.defineProperty
- 基础:
Object.defineProperty
是 ES5 引入的方法,用于直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回该对象。 - 单一属性操作:它一次只能定义或修改一个属性。
- 数据描述符和存取描述符:可以设置数据描述符(value, writable)和存取描述符(get, set)。
- 无法监听数组索引赋值和长度变化:对于数组,
defineProperty
不能监听到索引赋值和长度变化。 - 无法监听对象属性的添加和删除:它不能监听到对象属性的添加或删除操作。
- 性能影响:对于已经存在的对象属性进行操作时,性能影响较小。
Proxy
- 基础:
Proxy
是 ES6 引入的构造函数,用于创建一个对象的代理,从而实现基本操作的拦截和自定义行为(如属性访问、赋值、枚举、函数调用等)。 - 全面代理:它可以代理整个对象,而不是单个属性。
- 捕获器(traps) :
Proxy
提供了13种捕获器,可以拦截并定义基本操作的自定义行为。 - 监听数组索引赋值和长度变化:可以监听到数组索引赋值和长度变化。
- 监听对象属性的添加和删除:能够监听到对象属性的添加(
defineProperty
)和删除(delete
)操作。 - 性能影响:由于代理了整个对象,可能在某些情况下会有更大的性能开销。
具体区别
-
操作范围:
Object.defineProperty
:仅限于单个属性。Proxy
:代理整个对象。
-
拦截功能:
Object.defineProperty
:仅能通过设置set
和get
拦截属性的读取和设置。Proxy
:可以拦截包括但不限于属性的读取(get
)、设置(set
)、枚举(enumerate
)、删除(deleteProperty
)等13种操作。
-
对数组操作的支持:
Object.defineProperty
:无法有效监听数组索引的变动和长度的变化。Proxy
:可以监听数组的索引变动和长度变化。
-
对新增和删除属性的支持:
Object.defineProperty
:无法监听属性的新增和删除。Proxy
:可以监听属性的新增(通过defineProperty
)和删除(通过delete
操作)。
-
性能:
Object.defineProperty
:对于现有属性的操作性能较好。Proxy
:可能因为代理整个对象而带来额外的性能开销。
结论
在选择 Proxy
和 Object.defineProperty
时,如果需要代理整个对象并拦截多种操作,或者需要监听数组索引变化和对象属性的添加删除,Proxy
是更好的选择。如果只是需要针对对象的个别属性进行操作,且不需要考虑数组变化和属性的新增删除,Object.defineProperty
可能是更简单、更直接的选择。
42-Position有哪些会影响文档流的位置
- static:这是默认值。静态定位的元素处于正常的文档流中。它们的位置不会受到
top
、bottom
、left
和right
属性的影响。 - relative:相对定位的元素相对于其正常位置进行定位。使用
top
、bottom
、left
和right
属性可以设置元素相对于其正常位置的偏移。尽管元素的位置可能会改变,但它在文档流中的原始位置会被保留,也就是说,它仍然占据着原来的空间。 - absolute:绝对定位的元素相对于最近的非
static
定位的祖先元素进行定位。这意味着它们会脱离正常的文档流,不再占据原来的空间。它们的定位可以通过top
、bottom
、left
和right
属性来设置。 - fixed:固定定位的元素相对于浏览器窗口进行定位,并且它们也会脱离正常的文档流。与绝对定位类似,使用
top
、bottom
、left
和right
属性可以设置其位置,但它们不会随页面滚动而移动。 - sticky:粘性定位是相对和固定定位的混合体。一个粘性定位的元素在滚动到其指定的偏移之前,表现得像相对定位的元素(即在文档流中保持其位置)。当达到指定的偏移量时,它将表现得像固定定位的元素(即固定在指定位置,不随滚动而移动)。
总结来说,absolute
和fixed
定位的元素会脱离文档流,不再影响其他元素的布局,而relative
和sticky
定位的元素虽然可以改变位置,但仍然保留在文档流中,占据原来的空间。static
定位的元素则完全按照文档流的顺序和规则进行布局。
43-intanceof的原理
原理就是进行原型链的递归比较
function myInstance(instance,type){
if(instance===null)return false;
if(instance.__proto__ === type){return true;}
return myInstance(instance.__proto__,type);
}
44-ref和reactive的本质和原理
45-defineProperty和Proxy
46-MVVM详解
47-console.log([]===[])
答案为false。
因为===是严格比较,在比较基础类型的时候是进行值和类型的判断。
在对引用类型进行判断时,是对类型和地址进行判断。
48-const a= [1,2,3] 怎么做深拷贝,如果数据是不知道类型?
-
手写递归深拷贝,不需要原型链的属性
function deepClone(targetObj){ if (targetObj === null || typeof targetObj !== 'object') { return targetObj; } let newObj = {}; for(let attr in targetObj){ if(targetObj.hasOwnProperty(attr)){ newObj[attr] = deepClone(targetObj[attr]); } } return newObj; }
-
structuredClone(targetObj)
-
- MessageChannel();
const {port1,port2}=new MessageChannel();
port1.postMessage(obj);
port2.onmessage = e => console.log(e.data);//e.data就是新对象
-
JSON.parse(JSON.stringify)
49-子元素设置水平垂直居中
1-flex布局
.parent{
display:flex;
justify-content:center;
align-items:center;
}
2-gird布局
.parent{
display:grid;
justify-content:center;
align-items:center;
}
3-position:absolute + transform
.parent{
position:relative;
}
.child{
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
}
4-父元素position:absolute + 子元素position:absolute
.parent {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.child {
width: 200px;
height: 200px;
margin: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
50-let b = "aaa"这个字符串占的内存空间
存储在堆中,占的大小
- 每个字符 ‘a’ 占用2个字节。
- 因此,字符串
"aaa"
总共占用 3 * 2 = 6 个字节。
v8是将字符串存储在堆中。因为字符串可能很长造成栈的溢出,俗称爆栈。
51-常见的网络协议
传输控制协议(TCP)
TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。以下是TCP的一些关键特点:
- 面向连接:在数据传输之前,TCP需要建立一个连接,这个过程称为三次握手。在连接建立后,数据传输开始,并且在传输完成后,连接将被终止。
- 可靠性:TCP确保数据包的可靠传输。如果数据包在传输过程中丢失,TCP会重新发送这些数据包。
- 有序性:TCP保证数据包按发送顺序到达。
- 流量控制:TCP使用滑动窗口机制来控制数据流,避免发送方发送数据过快,接收方来不及处理。
- 拥塞控制:TCP监视网络拥塞情况,并相应地调整其传输速率。
三次握手过程:
- SYN:客户端发送一个SYN(同步序列编号)到服务器,以开始一个新的连接。
- SYN-ACK:服务器收到SYN后,会应答一个SYN-ACK(同步确认应答)。
- ACK:客户端收到SYN-ACK后,发送一个ACK(确认应答)作为响应。
超文本传输协议(HTTP)
HTTP是应用层协议,主要用于Web服务器和客户端之间的信息传输。以下是HTTP的一些关键特点:
- 无状态:HTTP协议本身是无状态的,这意味着服务器不会保存任何关于客户端过去请求的信息。
- 简单性:HTTP协议相对简单,易于理解和使用。
- 可扩展性:HTTP允许传输任意类型的数据,只需要在头部指定正确的Content-Type。
- 请求/响应模式:客户端发送请求,服务器返回响应。
HTTP请求和响应结构:
- 请求:包括请求行(方法、URL、HTTP版本)、请求头部、空行和可选的请求体。
- 响应:包括状态行(HTTP版本、状态码、状态短语)、响应头部、空行和响应体。
超文本传输协议安全(HTTPS)
HTTPS是HTTP的安全版本,它在HTTP和TCP之间添加了一个加密层,通常是TLS(传输层安全性)或SSL(安全套接字层)。以下是HTTPS的一些关键特点:
- 加密:HTTPS通过TLS/SSL对数据传输进行加密,保护数据不被窃听和篡改。
- 认证:HTTPS提供服务器认证,确保用户连接到的是预期的服务器。
- 完整性:HTTPS确保数据在传输过程中未被修改。
HTTPS工作流程:
- TCP连接:客户端和服务器首先建立TCP连接。
- TLS握手:在TCP连接建立后,客户端和服务器进行TLS握手,协商加密算法和交换密钥。
- 加密数据传输:一旦TLS握手完成,客户端和服务器使用协商好的密钥对HTTP数据进行加密传输。
- 结束TLS连接:当HTTP传输完成后,TLS连接将被终止。
HTTPS广泛用于网上银行、电子商务和其他需要处理敏感信息的网站,以确保数据的安全和隐私。随着网络安全意识的提高,HTTPS的使用也越来越普遍。
52-图片的格式?有什么不同
PNG(Portable Network Graphics)
-
用途:适用于网页设计、透明背景的图像、图标等。
-
特点
:
- 支持无损压缩,图像质量不会下降。
- 支持透明背景和半透明效果。
- 可以包含较长的文件名和详细图像数据。
- 支持交错(渐进显示),适合网络传输。
SVG(Scalable Vector Graphics)
-
用途:适用于矢量图形,如图标、图表、网页设计元素等。
-
特点
:
- 基于XML的矢量图像格式,文件大小通常很小。
- 可以无限放大而不失真。
- 支持动画和交互性。
- 不适合复杂的位图图像。
WebP
-
用途:适用于网络图像,特别是需要压缩的图片。
-
特点
:
- 由Google开发,旨在加快图片的加载速度。
- 支持有损和无损压缩。
- 通常比JPEG和PNG格式更小的文件大小,但保持了较高的图像质量。
- 支持透明背景和动画。
JPG / JPEG(Joint Photographic Experts Group)
-
用途:适用于照片和复杂图像。
-
特点
:
- 采用有损压缩,可以大幅减小文件大小,但会损失一些图像质量。
- 文件大小相对较小,适合网络传输。
- 不支持透明背景。
- 不适合包含文字或线条的图像,因为压缩可能会导致锯齿状边缘。
区别:
- 压缩类型:PNG和SVG通常是无损压缩,而JPG和WebP通常是有损压缩。无损压缩保留了图像的所有数据,而有损压缩则牺牲了一些质量以获得更小的文件大小。
- 文件大小:有损压缩的格式(如JPG和WebP)通常比无损压缩的格式(如PNG)文件大小更小。
- 图像质量:无损格式在放大时不会失真,而有损格式可能会出现模糊或压缩伪影。
- 透明度支持:PNG和WebP支持透明背景,而JPG不支持。
- 适用场景:SVG适用于矢量图形,PNG适用于需要透明度的图像,JPG适用于照片,WebP则适用于需要压缩的网络图像。
53-对称加密和非对称加密的区别
对称加密(Symmetric Encryption)
-
密钥的使用:
- 对称加密使用相同的密钥(或密码)进行加密和解密。
- 密钥必须保密,并且需要在通信双方之间安全地共享。
-
速度:
- 对称加密算法通常比非对称加密算法快得多,因为它们通常更简单。
-
算法示例:
- DES(Data Encryption Standard)
- AES(Advanced Encryption Standard)
- RC4(Rivest Cipher 4)
-
安全性:
- 安全性主要依赖于密钥的保密性。如果密钥泄露,加密的信息就可能被解密。
-
用途:
- 适用于大量数据的加密,如数据库加密、文件加密等。
非对称加密(Asymmetric Encryption)
-
密钥的使用:
- 非对称加密使用一对密钥:公钥和私钥。
- 公钥可以公开分享,用于加密信息;私钥保密,用于解密信息。
-
速度:
- 非对称加密算法通常比对称加密算法慢,因为它们涉及更复杂的数学运算。
-
算法示例:
- RSA(Rivest-Shamir-Adleman)
- ECC(Elliptic Curve Cryptography)
- DSA(Digital Signature Algorithm)
-
安全性:
- 安全性基于数学难题,如大数分解或椭圆曲线离散对数问题,这些问题在当前计算能力下难以解决。
-
用途:
- 适用于密钥交换、数字签名、安全电子邮件等。
主要区别总结:
- 密钥数量:对称加密使用一个密钥,非对称加密使用两个密钥(公钥和私钥)。
- 密钥分发:对称加密需要安全地分发密钥,而非对称加密的公钥可以公开分发。
- 性能:对称加密通常更快,非对称加密更慢。
- 安全性:对称加密的安全性依赖于密钥的保密性,而非对称加密的安全性依赖于数学难题。
- 用途:对称加密适用于加密大量数据,非对称加密适用于密钥交换和数字签名。
在实际应用中,对称加密和非对称加密经常结合使用,以充分利用它们的优势。例如,可以使用非对称加密来安全地交换对称加密的密钥,然后使用对称加密来加密实际的数据传输。
54-async & await 为什么比promise好
只是语法糖,本质还是promise,但是给我进行封装。使得更加的语义化。
并且代码更简洁,可以直接方便使用try,catch进行捕获。使用 async
/await
可以更容易地调试异步代码,因为开发者可以设置断点并在 await
语句处暂停执行。
55-js的几个异步操作
56-Vue3 diff vs Vue2 diff
Vue 3 中的虚拟 DOM diff 算法相较于 Vue 2 进行了多项优化,以提高性能和效率。以下是 Vue 3 diff 算法的一些主要优化点:
1. 双端比较算法
Vue 3 继承并改进了 Vue 2 的双端比较算法,该算法在比较新旧 children 的过程中,会从两个列表的头部和尾部开始比较,寻找相同节点,这样可以减少不必要的节点比较,提高比较效率。
2. 静态节点优化
Vue 3 中,编译器能够识别静态节点和静态子树,并在 diff 过程中跳过它们,因为这些节点在后续渲染中不会发生变化。这样可以减少不必要的比较和重渲染。
3. Block Tree
Vue 3 引入了 Block Tree 的概念,它将模板分割为多个块,每个块包含了动态节点的信息。在更新过程中,Vue 3 只需要遍历包含动态内容的块,而不是整个虚拟 DOM 树,这样可以大大减少更新时的计算量。
4. Fragment 和 Teleport
Vue 3 支持了 Fragment(允许组件有多个根节点)和 Teleport(允许将子节点渲染到 DOM 树的其他位置)等新特性,这些特性对 diff 算法也进行了相应的优化。
5. 更高效的节点复用
Vue 3 在节点复用时进行了优化,它会尽可能复用已有节点,减少创建新节点和删除旧节点的操作,从而提高性能。
6. 属性更新优化
Vue 3 对属性更新进行了优化,它只更新变化的属性,而不是全部重新设置属性,减少了 DOM 操作。
7. 事件监听器缓存
Vue 3 对事件监听器进行了缓存,避免了重复绑定和移除事件监听器,提高了效率。
8-块树 (Block Tree)
Vue 3 引入了块树的概念,它将模板分割为多个块,每个块包含了动态节点的信息。在 diff 过程中,只需要遍历包含动态内容的块,而不是整个虚拟 DOM 树。
具体优化点:
- 碎片 (Fragment) : Vue 3 允许组件有多个根节点,这在 Vue 2 中是不允许的,这需要对 diff 算法进行相应的调整。
- 静态提升 (Static Hoisting) : 静态节点和子树在 diff 过程中被提升,不会在每次渲染时重新创建。
- 编译时优化: Vue 3 的编译器在生成渲染函数时,会进行更多的优化,比如将动态节点集中在一起,减少运行时的开销。
- 动态节点优化: 动态节点的处理更加高效,比如动态属性和动态子节点的更新。
这些优化使得 Vue 3 在处理大型列表和复杂组件树时,能够提供更快的更新速度和更好的性能表现。
57-interface & type
nterface 不支持原始数据类型, type 支持
interface 支持继承, type不支持,但可组合
interface 用于类的实现,type适合于各种类型定义
interface 用于类的定义和约束, type 用于创建类型别名,简化复杂类型表达
interface 是面向对象设计模式,面向接口编程的核心概念
TypeScript 中的 type 和 interface:你真的了解它们的不同吗?在 TypeScript 这个强大 - 掘金 (juejin.cn)
58-三次握手,四次挥手
关于三次握手与四次挥手面试官想考我们什么?--- 不看后悔系列在面试中,三次握手和四次挥手可以说是问的最频繁的一个知识点 - 掘金 (juejin.cn)
想象你正在通过一个在线书店买书,这个过程就像计算机网络中的数据传输。
1. 应用层(Application Layer)
- 比喻:你选择了一本书,并点击“购买”按钮。
- 功能:应用层就像是你和书店的界面,它决定了你的请求(比如买书)如何被发送。
2. 传输层(Transport Layer)
- 比喻:书店确认你的订单,并安排快递。
- 功能:传输层确保你的购买请求(数据)被正确地发送和接收,就像快递公司确保包裹送达。
3. 网络层(Network Layer)
- 比喻:快递公司决定通过哪条路线将书送到你家。
- 功能:网络层负责找到数据传输的最佳路径,就像快递公司选择路线。
4. 数据链路层(Data Link Layer)
- 比喻:快递在每个中转站进行检查和转发。
- 功能:数据链路层确保数据帧(包裹)在网络中的每个跳点(中转站)之间正确传输。
5. 物理层(Physical Layer)
- 比喻:快递员驾驶卡车或摩托车运送包裹。
- 功能:物理层处理数据的实际传输,就像快递员使用交通工具运送包裹。
整个过程:
- 你(发送方)通过应用层告诉书店(接收方)你想要买书。
- 传输层确保这个请求被正确地发送。
- 网络层找到从书店到你的家的最佳路线。
- 数据链路层确保数据在每个中转站被正确处理和转发。
- 物理层实际传送数据,通过互联网的电缆和路由器等物理媒介。
这样,你可以把每一层想象成完成不同任务的步骤,就像在线购物的过程一样,每一步都确保了整个过程的顺利进行。
59-tailwind有什么有点?
- 响应式设计:Tailwind 内置了响应式设计工具,允许你通过简单的类名来控制不同屏幕尺寸下的样式,如
md:text-center
。 - 原子化CSS:Tailwind 采用原子化 CSS 的方法,这意味着每个类都是独立的,只负责一件事情,这有助于减少重复的 CSS 代码。
- 性能优化:由于减少了不必要的 CSS 代码,Tailwind 可以帮助减少最终生成的 CSS 文件的大小,从而提高页面加载速度
- 定制化:虽然 Tailwind 提供了大量的默认样式,但你可以很容易地通过配置文件来自定义样式,以满足你的设计需求。
60-js的几个异步操作
-
Promise
-
setTimeout
-
fetch
-
XMLHttpRequest
-
requestAnimationFrame
-
File API
-
Web Workers
61-宏任务和微任务
宏:
在 JavaScript 中,宏任务(macrotask)是一系列较大的任务,它们在事件循环中的处理顺序相对较低。常见的宏任务包括:
setTimeout(fn, 0)
:使用setTimeout
函数设置的定时器,即使设置为 0,也不会立即执行,而是被加入到宏任务队列中。setInterval(fn, 0)
:与setTimeout
类似,使用setInterval
设置的定时器,即使设置为 0,也不会立即执行。setImmediate
(Node.js 环境) :在 Node.js 中,setImmediate
用于在当前事件循环的所有任务完成后立即执行一个函数。- I/O 操作:如文件读取、网络请求等,这些操作完成后会作为宏任务被加入到队列中。
- 用户交互事件:例如点击事件、键盘事件等,这些事件处理函数会在事件触发后被加入到宏任务队列中。
requestAnimationFrame
:用于在浏览器下一次重绘之前执行的函数。requestIdleCallback
:在浏览器空闲时执行的函数,这个宏任务在浏览器绘制完成之后执行。MessageChannel
消息:MessageChannel
是一个高级 API,用于在不同的线程之间发送消息。postMessage
:在不同的窗口或标签页之间发送消息。importScripts
:在 Web Worker 中,用于加载脚本。XMLHttpRequest
事件:XMLHttpRequest
对象的回调函数,如onreadystatechange
。setImmediate
(旧版) :在旧版 Node.js 中,setImmediate
用于在当前事件循环的所有任务完成后立即执行一个函数。I/O
完成事件:例如,fs.write
、fs.read
等文件操作完成后的回调函数。
这些宏任务会在事件循环的适当时间点被处理,但它们的处理顺序低于微任务。在 JavaScript 的事件循环中,宏任务在所有微任务处理完成后执行
微:
- Promise 回调:
Promise
对象的.then()
,.catch()
, 和.finally()
方法。 - MutationObserver 回调:用于监视 DOM 变化的观察器。
- async/await 函数中的代码:在
async
函数中的代码,或者在await
表达式之后的代码。 - queueMicrotask:一个全局函数,允许你将一个函数排队为一个微任务。