前端面试题整理
HTML
npm和pnpm的区别
pnpm 是一个基于 npm 的包管理工具的替代品。与 npm 相比,pnpm 还具有一些其他的优势。例如,pnpm 可以自动检测并解决依赖关系冲突,可以通过并行安装来加快安装速度,并且可以在安装过程中进行增量更新,以减少网络和磁盘的使用。
总结来说,pnpm 是一个更加高效和快速的包管理工具,可以替代 npm 来管理 JavaScript 项目中的依赖包
语义化:增加代码可读性,有利于搜索引擎识别,爬虫获取更多信息;更好的展示代码结构
script标签中defer和async的区别:
相同点:async和defer都是异步加载js
不同点:async是立刻执行, defer在元素加载完之后执行
因此, js脚本加上 async或 defer,放在头部可以减少网页的下载加载时间,如果不考虑兼容性,可以用于优化页面加载的性能
webSocket:因为http是客户端到服务端的单向通信,如果服务器有变化,客户端就得不断向服务器发出询问,效率低且占内存,
所以就诞生了webSocket这种服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息的双向通信模式
webSocket在创建的时候必须传入一个url,发送数据用send(),只能发送字符串,服务器返回的数据在event.data中,也是字符串格式
要关闭连接用close()
http和https的区别:HTTP协议以明文方式发送内容,不提供任何方式的数据加密。HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。https则是具有安全性的ssl加密传输协议。
http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。并且https协议需要到ca申请证书。HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、
身份认证的网络协议,要比http协议安全。
CSS
回流:无论通过什么方式影响了元素在视图窗口内的位置和尺寸大小,浏览器需要重新计算元素在视图窗口内的几何属性,这个过程叫做回流
重绘:通过构造渲染树和回流阶段,我们知道了哪些节点是可见的,以及可见节点的样式和具体的元素在视口内的位置和尺寸大小,接下来就可以将渲染树的每个节点都转换为屏幕上的实际像素,
这个阶段就叫做重绘
css选择器:.class、#id、标签选择器、伪类选择器......
盒模型:盒模型分为标准盒模型和IE盒模型,两者都由content + padding + border + margin构成,区别在于content的计算不同,标准盒模型是content,IE盒模型是content+padding+border
水平垂直居中:绝对定位、flex、grid布局、table-cell + vertical-align + inline-block/margin: auto
子元素设置position:absolute,如果父元素设置了position那么就依照父元素做定位,如果父元素没设置就向上一级寻找,直到body停止
vh vw rem em 分别是什么
px代表物理屏幕上能显示出的最小的一个点,
em 是相对于父级的字体大小,
rem是相对于HTML根元素的字体大小,
vh 和vw相对于视口的高度和宽度,1vh 等于1/100的视口高度,1vw 等于1/100的视口宽度
BFC规则
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。
产生
1、根标签(html)
2、float的值不为none
3、overflow的值不为visible
4、display的值为inline-block
5、position的值为absolute或fixed
特点
1、属于同一个BFC的两个块元素,垂直margin兄弟关系会折叠(正数以大值为准,有负数正常加减),父子关系会塌陷。
2、BFC区域不会与float的标签区域重叠。
3、浮动的标签也会被计算BFC高度。
4、BFC是独立容器,内部标签不会影响到外部标签。
作用
防止塌陷;自适应两栏布局;清浮动
css预处理器的好处:提高样式效率;可维护性;更高的可读性;缺点: 增加代码复杂度;无法完全避免编码错误
less和sass区别
1. 编译环境不一样 Less是基于JavaScript,是在客户端处理的。Sass是基于Ruby的,是在服务器端处理的。
2. 变量符不一样,Less是@,而Scss是$。
3. 输出设置,Less没有输出设置,Sass提供4中输出选项:nested, compact, compressed 和 expanded。
4. Sass支持条件语句,可以使用if{}else{},for{}循环等等。而Less不支持。
5. 引用外部CSS文件 css@import引用的外部文件如果不想编译时多生成同名的.css文件,命名必须以_开头, 文件名如果以下划线_开头的话,Sass会认为该文件是一个引用文件,不会将其编译为同名css文件.
6. Sass和Less的工具库不同 Sass有工具库Compass, Less有UI组件库Bootstrap.
JS
new关键字是开辟一个存储空间
数据类型:number、string、boolean、undefined、null、function、array、object(es6新增symbol:代表独一无二的值,最大的用法是用来定义对象的唯一属性名)
判断数据类型的方法:typeof(typeof判断不出object和null,因为null被认为是一个空对象,返回都是object,array也判断不出,array用isArray判断),
instanceof 判断数据是否是某个对象的实例,返回一个布尔值,不能检测null和undefined
普通类型(值类型)的数据类型在定义的时候存在栈中,是一个值可以直接用;复杂类型的数据类型在定义的时候存在堆里面,是一个地址需要引用所以也叫引用类型
垃圾回收机制
var、let、const三者的区别:
var在同一作用域中可重复定义相同的变量名,变量值是最后一次定义的值,存在变量 提升;
let,const不能在同一作用域中重复定义相同的变量命,只在最靠近的一个块中有效不存在变量提升,let可以定义变量也可以定义常量,const定义的简单类型的数据不能修改可以修改数组或对象中的元素
this
(1)全局环境中,this默认绑定到window
(2)函数独立调用时,this默认绑定到window
(3)new调用,this是新建的对象
(4)箭头函数中的this是外部作用域中的this
(5)可以通过call()/apply()修改this指向
call,apply,bind的区别
相同点: 都是改变this指向的,都不会修改原先函数的this指向;
第一个参数都是this要指向的对象;
都可以利用后续参数传参
不同点:call和bind传的参数都是一一对应的
apply只有两个参数,第二个参数为数组
call和apply都是对函数进行直接调用,而bind方法返回的仍是一个函数
call和apply是改变后页面加载之后就立即执行,是同步代码。
bind是异步代码,改变后不会立即执行;而是返回一个新的函数
call、apply只是临时的修改一次,也就是call和apply方法的那一次;
bind是永久修改函数this指向,但是它修改的不是原来的函数;而是返回一个修改过后新的函数,此函数的this永远被改变了,绑定了就修改不了
宏任务和微任务的概念和执行逻辑
Js是由上而下执行的,在执行过程中会出现异步和同步的现象。宏任务是由浏览器或者node发起的,而微任务由JavaScript自身发起。
执行:先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步 微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕后,再将异步微任 务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程 执行,一直循环直至所有任务执行完毕(以上过程即为事件循环)
事件冒泡
当事件发生后,这个事件就要开始传播(从里到外或者从外向里)。为什么要传播呢?因为事件源本身(可能)并没有处理事件的能力,即处理事件的函数(方法)并未绑定在该事件源上
具体参考(https://blog.csdn.net/weixin_53291256/article/details/131697929)
事件委托:就是利用冒泡的原理,把事件加到父级上,通过判断事件来源的子集,执行相应的操作,事件委托首先可以极大减少事件绑定次数,提高性能;其次可以让新加入的子元素也可以拥有相同的操作。事件委托的关系是将子元素的事件委托到父元素上。
深浅拷贝
深拷贝:拷贝过程中会创造另一个一摸一样的对象,新旧对象不共享内存,改变新对象原对象不会改变,比如JSON.parse() 和 JSON.stringify()
浅拷贝:只拷贝基本的数据类型,不复制对象本身,新旧对象公用内存,比如赋值
cookie / localStorage/ sessionStorage的区别
共同点:都是保存在浏览器端、且同源的
Setitem/gititem localStorage/ sessionStorage
getCookie cookie
区别:
localStorage:最大的容量是5M,是H5新增的特性,本地存储的一个方案,不会每次都会和后台进行交互,除非手动删除,否则一直存在,缓存的数据在同源的窗口是共享的
sessionStorage:也是h5新增的特性,不回每次和台进行交互,,关闭浏览器,缓存失效,在同源的窗口是共享的
cookie:容量是4k每次都会和后台进行交互,可以设置过期时间,如果不设置过期时间那么视为随着浏览器窗口关闭而消失,如果设置了cookie的过期时间那么会把cookie保存在硬盘上,关闭后打开仍然有效,在同源的窗口是共享的,并且是始终在请求中携带
跨域
原因同源策略: 协议 域名 端口号
浏览器允许发起跨域请求,但是跨域请求的数据会被拦截
JsonP : 浏览器未对script标签没有采取同源策略
(1)前端利用了script发跨域请求【get】,自己定义一个function,function的参数是需要的数据,发请求的时候带着这个function的函数名;
(2)服务器接收到这个请求,在返回结果的时候,用接收到的函数名包裹数据返回,就是相当于服务器响应后直接调用前端定义的function,将前端需要的数据作为入参传进去
CORS:添加请求头信息实现跨域
Proxy:服务器代理
具体 https://blog.csdn.net/weixin_62889848/article/details/128559799
HTTP请求的常用响应状态码及解决方法
200 (成功) 服务器已成功处理了请求
301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302 (重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 (禁止) 服务器拒绝请求。
404 (未找到) 服务器找不到请求的网页。
405 (方法禁用) 禁用请求中指定的方法。
502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
Post请求及get请求
都是HTTP发送的请求方式
区别 :1.get请求时获取资源
2.post请求是交换资源
3.传输数据量上,get请求是受浏览器的url限制的,而post请求数据一般不在url上不受限制
4.get请求是明文传输,post请求相对安全一些
5.缓存问题
promise
ES6推出的更好的异步编程解决方案,通过promise.then的链式调用解决嵌套回调的回调地狱问题
原型
每个函数都有一个显示原型属性:prototype;
每个实例都有一个隐式原型属性:__proto__;
实例__proto__与对应的prototype都指向原型对象;
函数的默认的原型对象是Object的实例,也就是一个{};
原型对象上有一个constructor属性指向对应的构造函数;
原型链
从对象的__proto__开始,连接的所有对象,也可称为“隐式原型链
模块化开发的4点好处:
1 避免变量污染,命名冲突
2 提高代码复用率
3 提高维护性
4 依赖关系的管理
git常用命令
git init - 初始化仓库。
git add . - 添加文件到暂存区。
git commit - 将暂存区内容添加到仓库中
git merge 用来合并一个或者多个分支到你已经检出的分支中
1、分支创建 git branch (+分支名称)
2、查看分支 git branch
3、切换分支 git checkout (分支名)
4、合并分支 git merge(分支名)
5、删除分支 git branch -d (分支名)
6、创建并切换 git checkout -b (分支名)
git reset –hard 版本回滚
git pull 本地与服务器端同步
git push (远程仓库名) (分支名) 将本地分支推送到服务器上去。
数组、对象方法
array.concat合并 返回新数组 不改变原数组
Array.prototype.filter() 过滤 返回新数组
Array.prototype.find() 顾虑符合条件的第一个值
Array.prototype.flat() 递归遍历数组合并数组(不会去重)
Array.prototype.includes() 判断是否有莫一个值 返回布尔值
Array.prototype.indexOf() 查找目标元素索引 查不到返回-1
array.isArray 判断给定值是否为数组
Array.prototype.join() 拼接数组 返回字符串
Array.prototype.map() 加工数组 返回新数组
Array.prototype.reduce()
Array.prototype.slice() 切割数组
Array.prototype.toString() 返回这个数组的字符串
Array.prototype.splice() 增删改一体
Array.prototype.sort() 数组排序 更改原数组
Array.prototype.fill() 填充数组 改变原数组
Array.prototype.reverse()反转数组 改变原数组
Array.prototype.push() 末尾增 改变原数组
Array.prototype.unshift() 头增 改变原数组
Object.freeze() 冻结对象
Object.assign() 合并对象
js和ts的区别
ts有类型安全功能能在编码期间检测错误,这为开发人员创建了一个更高效的编码和调试过程。
ts增加了void,枚举,any,never等类型
ts 中引入了模块的概念,可以把声明、数据、函数和类封装在模块中
ts中interface和type的区别
interface:接口,TS 设计出来主要用于定义【对象类型】,可以对【对象】的形状进行描述。
type :类型别名,为类型创建一个新名称。它并不是一个类型,只是一个别名。
主要区别在于 type 一旦定义就不能再添加新的属性,而 interface 总是可扩展的
VUE
vue和react的区别
共同点
数据驱动视图,组件化,都使用虚拟dom
不同点
vue是灵活易用的渐进式框架,它对侦测数据的变化更敏感、更精确
React推崇函数式编程(纯组件),数据不可变以及单向数据流
React推荐的做法是JSX + inline style
, 也就是把 HTML 和 CSS 全都写进 js 中,即 all in js
; Vue 推荐的做法是 template 的单文件组件格式
双向绑定原理不同:react是通过setState修改数据
webpack
本质上就是打包工具,不是框架也不是库。
webpack 本身只能处理原生的 JavaScript 模块,但是 loader 转换器可以将各种类型的资源转换成 JavaScript 模块。这样,任何资源都可以成为 webpack 可以处理的模块。
Loader
因为 Webpack 只认识 JS,所以 Loader 将其他类型的资源进行转译的预处理工作。
Plugin
在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
Vue 的生命周期。
Vue:beforCreated()创建之前,可用于loading加载阶段
Created()创建后,常用来调接口
beforMounte()dom加载前
Mounted()dom加载完成
beforUpdated()数据更新页面没更新
Updated()数据页面都更新了
beforDestroyed()销毁前,数据和方法还可以用
Destroyed()销毁后,组件销毁,数据方法不可用
在第二次进入组件时,因为复用等原因有的生命周期函数不会被加载,此时可以用watch监听路由或者actived钩子函数处理
M - Model:模型,是应用程序中用于处理应用程序数据逻辑的部分,通常模型对象负责在数据库中存取数据
V - View: 视图,是应用程序中处理数据显示的部分,通常视图是依据模型数据创建的。
C - Controller: 控制器, 是应用程序中处理用户交互的部分,通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据
M - Model,Model 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑
V - View,View 代表 UI 组件,它负责将数据模型转化为 UI 展现出来
VM - ViewModel,ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步 View 和Model 的对象,连接 Model 和 View
vue双向绑定原理
通过Object.defineProperty()
来劫持各个属性的setter
,getter
,在数据变动时发布消息给订阅者,触发相应的监听回调
订阅者发布者
提前写好n个方法,在未来的某个时间段执行
路由守卫
全局路由守卫router.beforeEnter((to,from,next)=>{}),进路由前使用、router.afterEnter((to,from,next)=>{})进路由后使用
组件守卫beforeRouteEnter((to,from,next)=>{}),进组件时调用,beforeRouteLeave((to,from,next)=>{}),离开组件时调用
组件独享守卫beforeEnter((to,from,next)=>{})进入组件时被调用,区别就在于,想对那个路由进行权限控制就直接在其路由配置项中添加守卫,作用域也仅限于该路由
vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
State提供唯一的公共数据源,所有共享的数据统一放到store的state进行储存,相似与data,通过this.$store.state获取
mutations : 使用它来修改数据(类似于methods),通过this.$store.commit('方法名')提交mutations中的方法来更改状 态
getters: 类似于computed(计算属性,对现有的状态进行计算得到新的数据-------派生 )
actions: 发起异步请求,通过提交mutation来实现,可以包含异步操作,通过 this.$store.dispatch('方法名')分发action
modules: 模块拆分
优点:集中管理共享的数据,易于开发和后期维护;Vuex 的状态存储是响应式的,当 Vue 组件从 store中读取状态的时候,若 store 中的状态发生变化,能够触发响应式的渲染页面更新;
限定了一种可预测的方式改变数据, 避免大项目中, 数据不小心的污染
缺点:刷新浏览器,vuex中的state会重新变为初始状态 ;解决方案-插件 vuex-persistedstate
vue中为什么将数据定义在data里:
集中保存有利于管理;data里的属性可以被组件中的其他模块访问;Vue的响应式系统需要监视组件的数据变化,只有data属性中的属性才会被监视。
data中的数据写在return中是因为不使用return包裹,数据是全局可见,容易造成污染,包裹后是当前组件可见。
因为vue组件可以复用,为了防止data被复用,data就被定义为了函数
vue3初始数据在setup中定义一个返回对象存放
vue路由传参,query和params的区别
query用path编写传参地址,而params用name编写传参地址;query刷新页面时参数不会消失,而params刷新页面时参数会消失;query传的参数会显示在url地址栏中,而params传参不会显示在地址栏中。
Vue2及Vue3
利用Proxy(代理) 拦截data属性的操作
利用Reflect(反射) 对被代理对象的相应属性进行操作
组合API
Setup 所有组合API都在这个函数里操作
Ref定义基本数据类型的响应式
Reactive定义引用数据类型的相应式
Computed 定义计算属性
Wactch 监视
Vue3的生命周期函数
setup()方法实在beforeCreate及created前调用的,所以不需要了
beforeCreate -> use setup()
created -> use setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
errorCaptured -> onErrorCaptured
axios和fatch的区别
axios传一个对象,里面包含请求url和请求方法,参数
fetch传两个参数,第一个是请求url,第二个是请求的一些参数
Axios还有非常好的一点就是会自动对数据进行转化,而Fetch则不同,它需要使用者进行手动转化
Fetch没有拦截器功能,但是要实现该功能并不难,直接重写全局Fetch方法就可以办到
最大的不同点在于Fetch是浏览器原生支持,而Axios需要引入Axios库
React
生命周期
componentWillMount()该方法会创建一个虚拟DOM
componentDidMount()类似Mounted()在render 之后调用,可获取dom
componentWillUpdate()数据更新
componentDidUpdate()数据页面更新
componentWillUnmount()销毁前,可用于移除定时器等
项目上常见的hooks
为什么用hooks?组件更好的复用,易拆解测试
useState 初始化数据,初始化只初始化一次,返回一个数组,第一个元素的值,第二个元素是方法
useEffect 内部不能修改 state
useEffect四种状态
useEffect(()=>{});不传参,不传递第二个参数会导致每次渲染都会运行useEffect。然后,当它运行时,它获取数据并更新状态。然后,一旦状态更新,组件将重新呈现,这将再次触发useEffect,这就是问题所在
useEffect(()=>{ },[]) 传空数组仅在挂载和卸载的时候执行
useEffect(()=>{ },[count]) //count更新时执行,count是自定义的
useRef用来获取dom节点;返回一个可变的 ref 对象,该对象只有个 current 属性,初始值为传入的参数( null)。
可以把这个ref对象利用元素的ref属性绑定在dom元素上
useContext也就是和 class 组件的 context 同样的效果,将状态传递给孙子组件
useReducer是单个组件状态管理,组件通讯还需要 props
useState和useRef的区别
1: useState的值在每个rernder中都是独立存在的。而useRef.current则更像是相对于render函数的一个全局变量,每次他会保持render的最新状态。这种关系更像是js一个经典的案例:for循环中异步打印i的值,let声明的i就相当于每个都是独立作用域,互相之间不会干扰。var则反之。
2:useState值的更新会触发组件重新渲染,而useRef的current不会触发重渲染。
简单来说useState操作数据,useRef操作dom节点
useEffect和useMemo的区别
useMemo第一个参数需要返回一个函数,useEffect也可以返回一个函数
两者第二参数都可以放一个数组,里边的元素有着浅比较触发函数的作用
useMemo是dom更新前触发的,useuseEffect是dom更新后触发的
类组件和函数组件之间的区别
类组件可以使用其他特性,如状态和生命周期钩子,并且他有this
函数组件只能接收props渲染到页面,无状态组件,没有this,不能使用生命周期钩子
函数组件性能要高于类组件,因为类组件使用要实例化,而函数组件直接执行取返回结果即可,为了提高性能,尽量使用函数组件
受控组件和非受控组件
受控组件是 React 控制中的组件,并且是表单数据真实的唯一来源。
非受控组件是由 DOM 处理表单数据的地方,而不是在 React 组件中。
react组件传值方法
1.父子传值,2.有共同父组件通过父子传值实现同级传值,3.用useContext传值,4.自定义事件传值
react组件通信
redux
Redux是一个流行的JavaScript框架,为应用程序提供一个可预测的状态容器,Redux严格限制了数据只能在一个方向上流动
所有的数据(state)存储在store中,通过接收组件指令分发一份action,当一个store
接收到一个action,它将把这个action
代理给相关的reducer
。
reducer
是一个纯函数,它可以查看之前的状态,执行一个action
并且返回一个新的状态
虚拟dom和diff算法
虚拟DOM其实就是相对于浏览器的真实DOM所渲染出来的一个用来描述真实DOM结构的JS对象
用对象的方式来描述真实的 dom,并且通过对象与真实dom建立了一一对应的关系,那么每次 dom 的更改,我通过找到相应对象,也就找到了相应的dom节点,再对其进行新。这样,就能节省性能,因为js 对象的查询,比对整个dom 树的查询,所消耗的性能要少
Diff算法就是在虚拟DOM树从上至下进行同层比对,如果上层已经不同了,那么下面的DOM全部重新渲染。这样的好处是算法简单,减少比对次数,加快算法完成速度。
优化
css 放 ,js 脚本放 最底部。
减少 DOM 操作。
手写
求出字符串中所有数字的和