目录标题
- 1、说说你对react的理解?有哪些特性?
- 2、 说说React生命周期有哪些不同的阶段?每个阶段对应的方法是?
- 3、说说你对React中虚拟dom的理解?
- 4、说一说你对react hook的理解?
- 5、 说说react 中jsx语法糖的本质?
- 6、 说说React jsx转换成真实DOM的过程?
- 7、说说Real DOM和Virtual DOM的区别?优缺点?
- 8、说说React中setState执行机制?
- 9、 说说react的事件机制?
- 10、 如何使用css实现一个三角形?
- 11、如何通过原生js实现一个节流函数和防抖函数?
- 12、说说webpack中常见的loader?解决了什么问题?
- 13、SPA(单页应用)首屏加载速度慢怎么解决?
- 14、vue中自定义指令的理解,应用场景有哪些?
- 15、vuex的理解?
- 16、Vue组件之间通信的方式有哪些?(能够说出七种)
- 17、说一说你对视口的理解?
- 18、什么是发布订阅模式,写出其核心实现代码?
- 19、说说reduce方法的作用?自己手动封装一个reduce,写出其核心代码?
- 20、 props和state相同点和不同点?render方法在哪些情况下会执行?
- 21、shouldComponentUpdate有什么作用?
- 22、说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关系?
- 23、react新出来两个钩子函数是什么?和删掉的will系列有什么区别?
- 24、React的props.children使用map函数来遍历会收到异常显示,为什么?应该如何遍历?
- 25、React组件之间如何通信?
- 26、谈谈你对immutable.js的理解?
- 27、redux本来是同步的,为什么它能执行异步代码?实现原理是什么?中间件的 实现原理是什么?
- 28、redux中同步action与异步action最大的区别是什么?
- 29、redux-saga和redux-thunk的区别与使用场景?
- 30、在使用redux过程中,如何防止定义的action-type的常量重复?
- 31、CDN的特点及意义?
- 32、为什么for循环比forEach性能高?
- 33、说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
- 34、React render方法的原理,在什么时候会触发?
- 35、![] == ![],![] == [],结果是什么?为什么?
- 36、什么是闭包?应用场景是什么?
- 37、谈一谈你是如何做移动端适配的?
- 38、移动端1像素的解决方案?
- 39、弹性盒中的缩放机制是怎样的?
- 40、bind、call、apply 区别?如何实现一个bind?
- 41、什么是防抖和节流?有什么区别?如何实现?
- 42、什么是响应式设计?响应式设计的基本原理是什么?如何做?
- 43、怎么理解回流跟重绘?什么场景下会触发?
- 44、说说vue中的diff算法
- 45、说说你对keep-alive的理解
- 46、如何解决跨域问题
- 47、Vue组件之间的通信方式都有哪些?
- 48、VUE路由的原理?
- 49、React 性能优化的手段有哪些
- 50、简述在浏览器中输入url地址 到浏览器呈现出页面发生的整个过程
- 51、SPA首屏加载速度慢的怎么解决
- 52、说说你对webSocket的理解
- 53、说说如何借助webpack来优化前端性能
- 54、AMD、CMD、commonJS模块化规范的区别?
- 55、说说Connect组件的原理是什么?
- 56、说说你对受控组件和非受控组件的理解?应用场景?
- 57、说说package.json中版本号的规则
- 58、说说你对koa中洋葱模型的理解?
- 59、 如果需要手动写动画,你认为最小时间间隔是多久,为什么?
- 60、 介绍一下你对浏览器内核的理解?
- 61、大文件如何做断点续传?
- 62、说说javascript内存泄漏的几种情况?
- 63、谈谈你对BFC的理解?
- 64、说出三种前端清除浮动的方法
- 65、什么是强缓存和协商缓存
- 66、说说git常用的命令有哪些?
- 67、说说你对git rebase 和git merge的理解?区别?
- 68、说说你对栈、队列的理解?应用场景?
- 69、说说TCP为什么需要三次握手和四次挥手?
- 70、原生js如何实现上拉加载下拉刷新?
- 71、说说你对事件循环的理解?
- 72、说说设备像素、css像素、设备独立像素、dpr、ppi之间的区别
- 73、React render方法的原理,在什么时候会触发?
- 74、说说你对vue中mixin的理解?
- 75、说说Real diff算法是怎么运作的?
- 76、说说你对redux中间件的理解?常用的中间件有哪些?实现原理?
- 77、说说React生命周期中有哪些坑?如何避免?
- 78、调和阶段setState干了什么?
- 79、 说说redux的实现原理是什么,写出核心代码?
- 80、React合成事件的原理?
- 81、为什么react元素有一个$$type属性?
- 82、说说你对fiber架构的理解?解决了什么问题?
- 83、说说你对事件循环event loop的理解?
- 84、数组常用方法及作用,至少15个?
- 85、for…in循环和for…of循环的区别?
- 86、Js数据类型判断都有哪几种方式?至少说出5种?它们的区别是什么?
- 87、说说你对Object.defineProperty()的理解?
- 88、说说react中onClick绑定后的工作原理?
- 89、react中setState和replaceState的区别?
- 90、说说你对useEffect的理解,可以模拟哪些生命周期?
1、说说你对react的理解?有哪些特性?
React是用于构建用户界面的Javascript库,只提供了UI层面解决方案。
遵循组件设计模式、声明式编程范式和函数式编程概念,使前端应用程序更加高效
特性:JSX语法、单项数据绑定、虚拟DOM、声明式编程、Component
它遵循从高阶组件到低阶组件的单向数据流。
优势:高效灵活、声明式设计、组件式开发、单向数据流比双向绑定更安全,速度更快。
2、 说说React生命周期有哪些不同的阶段?每个阶段对应的方法是?
挂载阶段:
Constructor()在react组件挂载之前,会调用他的构造函数
componentWillMount:在调用render方法之前调用,并在初始化挂载及后续更新的时候都会被调用
componentDidMount:在组件挂载的时候立即调用
更新运行阶段:
ComponentWillReceiveProps:在接收父组件改变后的props需要重新的渲染组件的时候用的比较多,外部组件传递频繁的时候会导致效率比较低
ShouldComponentUpdate:用于控制组件重新渲染的生命周期,state发生变化的时候,组件会进入冲洗你的渲染流程当中,在这里return false就可以阻止组件的更新
Render():是class组件中唯一的必须实现的方法
ComponentWillUpdate():这个方法是在等ShouldComponentUpdate返回true的时候,组件会进入重新渲染完成之前的进行这个函数
ComponentDidUpdate():每次state改变并重新渲染页面后都会进入这个生命周期
卸载或者销毁的阶段:
ComponentWillunMount():在此处完成组件的卸载和数据的销毁
3、说说你对React中虚拟dom的理解?
虚拟dom不会进行排版与重绘的操作,而真实dom会频繁的排版与重绘,虚拟dom的总损耗是“虚拟dom增删改+真实dom的差异增删改+排版与重绘”它的优势是简单方便,如果使用手动的操作真实dom来完成页面,繁琐又很容易出错,在大规模的应用下维护起来也比较困难,性能方面使用虚拟dom能够有效的去避免真实dom树的频繁更新,减少多次引起的重绘与回流,从而的去提高性能;跨平台:react借助虚拟dom带来了跨平台的能力,一套代码多段运行;
虚拟dom的缺点:在一些性能要求极高的应用当中虚拟dom无法进行针对性的极致优化,首次渲染大量dom的时候,由于多了一层虚拟dom的计算,速度要比正常的稍慢
4、说一说你对react hook的理解?
常见的hooks有useMemo、useState、useEffect、useCallBack、useRef、useContext、
Hooks主要就是通过创建的hooks来解决性能提升
通过自定义的hooks,可以将组件逻辑提取到可重复利用的函数当中,可以理解为hooks,就是为了用来放一些重复代码的函数,其中最常见的hooks就是useMemo是通过proComponent来对数据进行一次浅比较在引入hooks特性后我们可以中memo进行性能的提升,usecontext:它是可以将全局数据通过provider接口传递value给局部组件,让它包围在provider的接口可以全局数据的读写接口。
5、 说说react 中jsx语法糖的本质?
Jsx语法糖实质上就是一个js函数,需要babel来解析,核心函数是react.createElement(tag.(attrbuties),children)参数tag是标签名,可以是html标签和组件名attrbuties参数是标签的属性,children参数是tag的子元素,用来创建一个vnode,最后渲染到页面上。
jsx是一种语法扩展,<></>这种写法就是jsx,jsx编写的组件通过预处理babel解析后,再交给React库渲染到指定的父容器下,形成最终html页面。
使用jsx编写模板更加简单快速。
Jsx执行更快,因为JavaScript进行了优化。
6、 说说React jsx转换成真实DOM的过程?
使用react.createElement或者JSX编写react组件,实际上所有的JSX代码都会转换成react.createElement内容,babel帮助我们完成了转换的过程,createElement函数对key和ref等特殊的props进行了处理,并获取defaultProps对默认的props进行赋值,并且对传入的子节点进行处理,最终构造成一个dom对象
7、说说Real DOM和Virtual DOM的区别?优缺点?
虚拟dom不会进行排版与重绘的操作,而真实dom会频繁排版与重绘
虚拟dom的总损耗是“虚拟dom增删改+真实dom差异增删改+排版与重绘”,而真实的dom的总损耗是“真实dom完全增删改+排版与重绘”
真实dom的优势是易用;缺点是:效率低,解析速度慢,内存占用量过高;性能差:频繁的操作真实DOM,易于导致重绘与回流
虚拟dom的优势是简单方便,如果使用手动操作真实dom来完成页面,繁琐又很容易出错,在大规模的应用下维护起来也很困难,性能方面使用Virtual DOM,能够有效的去避免真实DOM树频繁的更新,减少多次引起的重绘与回流,从而提高性能;
跨平台:react借助虚拟dom,带来了跨平台的能力,一套代码多段运行;
缺点:在一些性能要求极高的应用当中虚拟dom无法进行针对性的极致优化。首次渲染大量的DOM的时候,由于多了一层虚拟dom的计算,速度要比正常的稍慢
8、说说React中setState执行机制?
一个组件的显示形态可以由数据状态和外部参数所决定,而数据状态就是state,当需要修改里面的值的状态需要通过调用setState来进行改变,从而达到更新组件数据的作用;
SetState第一个参数可以是一个对象,或者是一个函数,而第二个参数就是一个回调函数
用于可以实时的获取更新之后的数据;
在使用setState更新数据的时候,setState分为同步更新和异步更新,在组件生命周期或react合成事件中,setState是异步的;在setTimeout或者原生dom事件中,setState是同步的
总结就是对同一个值进行多次setState,setState的批量更新策略就会对其进行覆盖,取最后一次的执行结果
9、 说说react的事件机制?
React的事件机制:react上注册时间最终会绑定在document这个DOM上,而不是react组件对应的DOM,所有的时间都绑定在document上,其他节点没有绑定属性;
React自身的话实现了一套时间冒泡机制,所以这也就是为什么我们event.stopPropagation无效的原因;
react通过队列的形式,从触发的组件向父组件回溯,然后调用他们在JSX中定义的Callback;
React有一套自己的合成事件就是SyntheticEvent。
React事件机制就是在操作react中,我们会给对应的事件绑定上dom操作。就是事件冒泡机制。
事件机制就是分为同步操作和异步操作,先执行同步操作的,其余任务先放在任务队列,然后等同步的执行完毕,才调用异步任务的执行。
e就是事件对象。像E.target.value就是获取值。
事件机制也有合成事件。
浏览器事件的执行需要经过三个阶段,捕获阶段-目标元素阶段-冒泡阶段。
10、 如何使用css实现一个三角形?
写一个宽高为0的盒子;
选择一个为三角形的底边,将此便捷设置为一个颜色,另外三边设置为另外一个衍射,既可以显示三角效果
11、如何通过原生js实现一个节流函数和防抖函数?
节流和防抖就是两种可以节省性能的变成技术,两者的目的都是为了优化性能,去提高用户体验,都是基于dom时间限制正在执行的JavaScript数量的方法;
防抖触发高频时间后n秒内函数只会执行一次如果n秒内高频时间再次被触发,则重新计算时间,强制一个函数在一段时间内没有被调用之前不会被再次调用
节流会强制执行一个函数在一段时间内可以被调用最大的次数。
如何实现防抖,假设,仅当100毫秒过去了而没有被调用的时候才会执行此函数。用户在不断的输入值的时候,用防抖来节约请求资源
节流:假设最多每100毫秒执行一次此函数高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率,鼠标不断电机触发,mousedown
12、说说webpack中常见的loader?解决了什么问题?
在webpack内部中,任何文件都是模块不仅仅是js文件,默认情况下在遇到import或者require加载模块的时候webpack只支持对js和json文件打包,像css、sass、png等这类文件webpack则无法解析,这个时候就需要配置对应的loader进行文件内容的解析
Css解析css的css-loader styles-loader
解析less的less-loader 、sass的sass-loader
解析图片以及音频资源url-loader
Js解析将ts转化为js的ts-loader
13、SPA(单页应用)首屏加载速度慢怎么解决?
首屏时间,指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容
首屏加载可以说是用户体验中最重要的环节。
加载慢的原因:
- 网络延时问题
- 资源文件体积是否过大
- 资源是否重复发送请求去加载了
- 加载脚本的时候,渲染内容堵塞了
解决方案:
- 减小入口文件积
- 静态资源本地缓存
- UI框架按需加载
- 图片资源的压缩
- 组件重复打包
- 开启GZip压缩
- 使用SSR
14、vue中自定义指令的理解,应用场景有哪些?
指令系统是计算机硬件的语言系统,也叫机器语言,它是系统程序员看到的计算机的主要属性。
我们看到的v-开头的行内属性,都是指令。
注册一个自定义指令有全局注册与局部注册。
全局注册主要是通过vue.directive方法进行注册。
Vue.directive第一个参数是指令的名字(不需要写上v-前缀),第二个参数可以是对象数据,也可以是一个指令函数。
局部注册通过在组件options选项中设置directive属性,然后你可以在模板中任何元素上使用新的 v-focus property。
自定义指令也像组件那样存在钩子。
v-model是双向绑定数据能从data流向页面,也能从页面流向data。
v-bind是单向数据绑定,用来绑定数据和属性以及表达式,数据只能从data流向页面。
inserted是被绑定元素插入父节点时调用。
应用场景:
- 表单防止重复提交
- 图片的懒加载
- 一键copy的功能
15、vuex的理解?
Vuex是一个专门为vue.js 应用开发程序的状态管理模式,存在的目的是共享可复用的组件状态。可以解决组件之间数据共享的问题。
Vuex应用的本质是一个store仓库。
Store :存储数据、存储状态。
Getter:store中的计算属性。
Mutations:更改store中的状态
Actions:任意异步操作的。
Modules : 分隔模块的。
Vuex是适合用在大型项目中的,一般在大型项目中推荐使用Vuex。可以解决页面组件较多,数据难以维护的问题。
Vuex优点是减少了Ajax请求次数,可以直接从内存中的state获取数据。
16、Vue组件之间通信的方式有哪些?(能够说出七种)
- 通过props传递 : 使用于父组件传递给子组件
- 通过$emit触发自定义事件 : 使用于子组件传递给父组件
- 使用ref : 父组件在使用子组件的时候设置ref ,父组件通过设置子组件ref来获取数据
- EventBus : 使用于兄弟组件传值
- parent或者root : 通过共同祖辈 p a r e n t 或者 parent或者 parent或者root搭建通信
- attrs与listeners : 适用于祖先传递数据给子孙
- Provide与inject : 在祖先组件定义provide属性,返回传递的值。在后代组件通过inject接收组件传递过来的值
- Vuex : 使用于复杂关系的组件数据传递
17、说一说你对视口的理解?
视口可以分为布局视口、视觉视口、理想视口。
视口简单来说就是浏览器显示页面内容的区域。
在PC端,正常的视口宽度就是整个浏览器的窗口可视区的宽度,会随着浏览器窗口大小的重置而缩放;
视觉视口:视觉视口是指用户当前看到区域即设备宽度
布局视口:可以理解成一个盒子,但是和pc端不同的是,它是固定的,既不会变大变小。移动设备的浏览器都默认设置了一个viewport标签,定义了一个虚拟的布局视口,css布局将会根据他来进行计算,并被约束。
理想视口:可以用rem适配
18、什么是发布订阅模式,写出其核心实现代码?
发布订阅 就是基于一个事件通道,希望接受通知的对象Subscriber通过自定义事件订阅主题,被激活事件的对象Publisher通过发布主题事件的方式通过各个订阅该主题的Subscriber对象。
发布订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都将得到通知。
发布订阅模式会运用在 : 按钮点击事件,以及promise实现
19、说说reduce方法的作用?自己手动封装一个reduce,写出其核心代码?
reduce是遍历数组的方法,类似于map、forEach可以设置初始值。
- previousValue:上一次调用回调函数时的返回值,或者初始值
- currentValue:当前正在处理的数组元素
- currentIndex:当前正在处理的数组元素下标
- array:调用reduce()方法的数组
- initialValue:可选的初始值(作为第一次调用回调函数时传给 previousValue 的值)
var arr = ['a', 'b', 'c', 'd'];
result = arr.reduce(function (pre, item) {
console.log('pre: '+ pre + ';item: '+ item);
return pre+item;
});
console.log('result: ' + result);
20、 props和state相同点和不同点?render方法在哪些情况下会执行?
props是一个外部传进组件的参数,由于React具有单向数据流的特性,所以他的主要作用是从父组件向子组件中传递数据,它是不可改变的,如果想要改变它,只能通过外部组件传入新的props来重新渲染子组件,否则子组件的props和展示形式不会改变,props除了可以传字符串,数字,还可以传递对象,数组甚至是回调函数。
state主要作用是用于组件保存的,控制及修改自己的状态,它只能在constructor中初始化,state是可变的,state放改动的一些属性,比如点击选中,再点击取消,类似这种属性就放入带state中。
注意:没有state的叫做无状态组件,多用props少用state,多写无状态组件。
注意:修改state的值时,必须通过调用setState方法,当我们调用this.setState方法时,React会更新组件的数据状态,并且重新调用render方法。
在React 中,类组件只要执行了 setState 方法,就一定会触发 render 函数执行,函数组件使用useState更改状态不一定导致重新render。
所以,一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染。
21、shouldComponentUpdate有什么作用?
shouldComponent函数是React中的一个生命周期函数,用于更新组件前检查数据是否有变化,从而决定是否重新渲染组件。
shouldComponentUpdate函数的作用:
(1)、提升组件性能:当组件在接受到新的props和state时,可以通过shouldComponentUpdate判断是否需要重新渲染,减少不必要的渲染。
(2)、允许控制:React通过此函数允许开发者控制组件是否重新渲染,能够提高开发效率,实施预期操作。
22、说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关系?
虚拟DOM的本质是一个js对象,是真实dom的抽象,状态变更时记录新旧dom树的差异,最后把差异更新到真实dom中去,react虚拟dom是在浏览器端用js实现了一套dom接口,基于react进行开发时所有的dom构造都是通过虚拟dom进行。
当数据发生变化是,react重新构建整个dom树,
然后react将当前整个dom树和上一次的dom树进行对比,得到dom结构的区别。
key 当同一层级的某个节点添加了对于其他同级节点唯一的key属性,当它在当前层级的位置发生了变化后。react diff算法通过新旧节点比较后,如果发现了key值相同的新旧节点,就会执行移动操作(然后依然按原策略深入节点内部的差异对比更新),而不会执行原策略的删除旧节点,创建新节点的操作。
23、react新出来两个钩子函数是什么?和删掉的will系列有什么区别?
新出的钩子函数: getDerivedStateFromProps和getSnapshotBeforeUpdate
componentWillReceiveProps实际行为与命名并不相符,由于不稳定性用getDerivedFromProps代替
而componentWillUpdate同等理由被getSnapshotBeforeUpdate代替。
为什么删掉will?
三个钩子函数是被废弃,但是不是直接不能用了,而是官方会给出警告并推荐我们在这三个钩子前添加UNSAFE_前缀。
为什么被废弃呢,因为使用率并不太高,这三个钩子很容易被误解和滥用,这几个钩子不稳定。
24、React的props.children使用map函数来遍历会收到异常显示,为什么?应该如何遍历?
在react中props.children不一定是数组
有三种可能:
1、当前组件没有子节点数据类型就是undefined。
2、有一个子节点数据类型就是object
3、有多个子节点的时候才会是array,只要在多个节点的时候才可以直接调用map方法,
react自身提供了一个react.children.map()方法,可以安全遍历子节点对象。
25、React组件之间如何通信?
(1)、父传子:在父组件中定义一个常量,⽗组件可以通过 props的⽅式来向⼦组件传递。子组件通过this.props就可以获取父组件的值和常量。
(2)、子传父:父组件定义一个方法,子组件想要传递给父组件,就去调用这个方法,可以采用props+回调的方式
(3)、兄弟组件通信:可以通过兄弟节点的共同父节点,由父节点转发信息,实现兄弟间通信。
(4)、跨层级通信:context状态树
(5)、消息订阅与发布
(6)、hooks中的useContext和useReducer
26、谈谈你对immutable.js的理解?
immutable是不可变的,指一旦创建,就不能再被更改的数据
对immutable对象的任何修改或者添加删除操作都会返回一个新的immutable对象,
immutable实现的原理是持久化数据结构
用一种数据结构来保存数据
当数据被修改时,会返回一个对象,但是新的对象会尽可能的利用之前的数据结构而不会对内存造成浪费。
也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变,同时为了避免deepCopy把所有节点都复制一遍带来的性能损耗。immutable使用了就够共享。
如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其他节点则进行共享。
27、redux本来是同步的,为什么它能执行异步代码?实现原理是什么?中间件的 实现原理是什么?
用redux执行同步的时候,都是先发起一个dispatch(actionCreator())
1.先在actionCreator()中生成一个action对象。
2.由dispatch方法将action传到reducer。
3.reducer中计算新state
4.新state保存到store中
5.因为容器组件将state作为props传给展示组件,state更新后,展示组件渲染更新的部分(因为props更新了)
app中的各部分都有纯粹而限定的职责,reducer只负责计算新state、P组件只负责渲染、C组件只负责获取update后的state和disptach方法传递给P组件。
而异步操作,同样被归类为一种action(action可能会改变state)。所以异步操作的代码被放到action creator的返回值里,但是dispatch方法只能接收js对象
28、redux中同步action与异步action最大的区别是什么?
同步action: 执行了dispatch函数之后,对应的reducer纯函数立即得到执行,reducer执行完了之后,state立即就改变了,此时用store.getState函数,取到的是最新的state值。
异步action:原则上redux并没有提供异步action的处理方案,异步的action需要依赖第三方的中间件,目标state并不会立即响应,而是要看异步函数内部的逻辑,来决定state什么时候响应。
29、redux-saga和redux-thunk的区别与使用场景?
redux-thunk就是用来异步操作、接口请求的,使用之前需要先进行下载安装才能使用。
redux-thunk通过对dispatch进行升级,让dispatch可以接受函数
redux-thunk可以将异步逻辑放在actionCreator里面
应用场景:
redux-thunk应用场景:
dispatch一个action之后,到达reducer之前,进行一些额外的操作,就需要用到middleware。你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。
换言之,中间件都是对store.dispatch()的增强。redux-thunk就是用来异步操作,比如接口请求等。
redux-saga应用场景:
redux-sage和redux-thunk作用类似,redux-saga是一个用于管理redux应用异步操作的中间件,redux-saga通过创建sagas将所有异步操作逻辑收集在一个地方集中处理,可以用来代替redux-thunk中间件。
30、在使用redux过程中,如何防止定义的action-type的常量重复?
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。
Symbol函数前不能使用new命令,否则会报错,这是因为生成的symbol是一个原始类型的值,并不是对象。
Symbol函可以接受一个字符串作为参数,表示对Symbol实例得描述,主要是为了再控制台显示,或者转为字符串时,比较容易区分。
31、CDN的特点及意义?
CDN全程是Content Delivery Network,即内容分发网络。
CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络堵塞,提高用户访问响应速度和命中率。
CDN的关键技术主要有内容存储和分发技术。简单来说,CDN就是根据用户位置分配最近的资源。
CDN 的特点
- 本地缓存加速
- 镜像服务
- 远程加速
- 带宽优化
- 集群抗攻击
32、为什么for循环比forEach性能高?
for循环
就是通过下标,对循环中的代码反复执行,功能强大,可以通过index取得元素。处理比较复杂的处理的时候比较方便。
forEach()循环方法用于调用数组的每个元素,并将元素传递给回调函数。foreach有的也叫做增强for循环,forEach其实是for循环的一个特殊简化版。forEach循环对于空的数组是不会执行回调函数的。
- 遍历:for循环按照顺序进行遍历,forEach使用iterator迭代器遍历
- 数据结构:for循环是随机访问元素,foreach是顺序链表访问元素
- 性能上:对于数组arraylist来说,是顺序表,使用for循环可以进行顺序访问,速度比较快;使用foreach循环会比for循环稍微慢一点。对于linedlist来说,是单链表,使用for循环每次都要从第一个元素读取next域来读取,速度非常慢;使用foreach可以直接读取当前的节点,数据较快。
33、说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?
reduxjs/toolkit:
Redux 官方强烈推荐,开箱即用的一个高效的 Redux 开发工具集。它旨在成为标准的 Redux 逻辑开发模式,使用 Redux Toolkit 都可以优化你的代码,使其更可维护
react-redux:
react官方推出的redux绑定库,react-redux将所有组件分为两大类:UI组件和容器组件,其中所有容器组件包裹着UI组件,构成父子关系。容器组件负责和redux交互,里面使用redux API函数,UI组件负责页面渲染,不使用任何redux API。容器组件会给UI组件传递redux中保存对的状态和操作状态的方法
34、React render方法的原理,在什么时候会触发?
原理:
在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件
render函数中的jsx语句会被编译成我们熟悉的js代码,在render过程中,react将新调用的render函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新dom树
触发时机:
类组件调用 setState 修改状态
函数组件通过useState hook修改状态
一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行
render方法,一旦父组件发生渲染,子组件也会渲染
35、![] == ![],![] == [],结果是什么?为什么?
根据运算符优先级,!的优先级是大于==的。所以先会执行 ![]
! 可将变量转换为boolean类型,null、undefined、NaN以及空字符串(“)取反都为true,其余都为false。
所以! [] 运算后的结果就是false。
也就是[] == ! [] 相当于[] == false
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a8LitI8c-1681715725136)(C:\Users\86131\AppData\Roaming\Typora\typora-user-images\image-20230317095622037.png)]
36、什么是闭包?应用场景是什么?
可以访问外部函数中的变量的内部函数,
在js中只有函数内部的子函数才能读取局部变量,
闭包就是将函数内部和函数外部连接起来的桥梁,让外部访问函数内部变量,
局部变量常驻在内存中,可以避免使用全局变量,防止全局变量污染,
会造成内存泄漏,每次执行外部函数的时候,
外部函数的引用地址不同,都会创建一个新的地址
应用场景:
-
创建私有变量和延长变量的生命周期
-
setTimeOut传参
-
回调
-
封装变量
-
为节点循环绑定click事件
-
柯里化函数
37、谈一谈你是如何做移动端适配的?
px + viewport适配
rem布局
。CSS3媒体查询适配
。基于设计图的rem布局
。基于屏幕百分比的rem布局
。小程序的rpx布局
vw布局
。通过媒体查询的方式即CSS3的meida queries
。以天猫首页为代表的flex弹性布局
。以淘宝首页为代表的rem+viewport缩放
。rem方式
38、移动端1像素的解决方案?
- 使用伪类缩放
- 使用 -webkit-min-device-pixel-ratio
- 使用box-shadow模拟
- 使用图片
- 使用viewport+rem实现
- 使用伪类 + transform实现
- 用多背景渐变实现
39、弹性盒中的缩放机制是怎样的?
弹性盒中的项目设置flex-grow属性定义项目的放大比例,默认值为0,值越大,放大越厉害,且不支持负值;
而flex-shrink属性定义项目的缩小比例,默认值为1,数值越大,缩小越厉害,同样不支持负值。
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间,浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,也就是项目的本来大小。
注意:它可以设为跟width或height属性一样的值,比如给具体的像素值,则项目将占据固定空间。
40、bind、call、apply 区别?如何实现一个bind?
三者都可以改变函数的 this 对象指向
三者第一个参数都是 this 要指向的对象,如果如果没有这个参数或参数为 undefined 或 nu11,则默认指向全局 window
三者都可以传参,但是 apply 是数组,而 cal1 是参数列表,且 apply 和 ca1 是一次性传入参数,而 bind
可以分为多次传入
bind 是返回绑定this之后的函数, apply 、 call 则是立即执行
如何实现一个bind?
- 修改this指向
- 动态传递参数
- 兼容new关键字
41、什么是防抖和节流?有什么区别?如何实现?
防抖:在用户多次触发事件,当用户停止触发事件,将事件执行一次。等待一段时间。
节流:在用户多次触发事件,会在多次触发的过程中,间隔执行事件。按照一定的频率执行。
相同点:
都可以通过setTimeOut实现,目的都是降低回调执行效率,节省计算资源
不同点:
函数防抖,在一段连续操作结束后,处理回调,利用clearTimeOut和setTimeOut实现。
函数节流,在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能。
函数防抖关注一定时间连续触发的事件,只在最后执行一次,而函数节流一段时间内只执行一次。
42、什么是响应式设计?响应式设计的基本原理是什么?如何做?
什么是响应式设计:
-
指在同一页面在不同屏幕尺寸下有不同的布局。能够使一张页面适配多种屏幕的布局方案。
-
响应式开发一套界面,通过检测视口分辨率,针对不同客户端在客户端做代码处理,来展现不同的布局和内容
如何实现?
-
rem
-
vw / vh
-
弹性盒子
-
媒体查询
-
浮动
-
百分比
43、怎么理解回流跟重绘?什么场景下会触发?
回流:布局引擎会根据各种样式计算每个盒子在页面的大小与位置。
重绘:当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制。
回流触发时机:
- 添加或删除可见的DOM元素
- 元素的位置发生变化
- 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
- 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
- 页面一开始渲染的时候(这避免不了)
- 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
重绘触发时机:
- 颜色的修改
- 文本方向的修改
- 阴影的修改
44、说说vue中的diff算法
diff算法是一种通过同层的树节点进行比较的高效算法。
只会在同层级比较,不会跨层级比较。
在diff算法的过程中,循环从两边向中间比较。
在vue中作用于虚拟dom渲染成真实dom的新旧节点比较。
原理是当数据发生改变时,订阅者就会给真实的dom打补丁,来更新相应的视图。
45、说说你对keep-alive的理解
- keep-alive是vue中内置的组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
- keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
- 使用了keep-alive的组件后,组件就会自动加上activated钩子和deactivated钩子。
- 可以用在查看表格某条数据详细页,可以查看填写的表单内容路由跳转返回是是否还在。
46、如何解决跨域问题
跨域的本质时浏览器基于同源策略的一种安全手段,同源是指协议、域名、端口号相同,不相同就会出现跨域问题。
解决跨域的方法:
-
JSONP
-
CORS
-
Proxy事件代理
九种跨域解决方案:
1、JSONP跨域
2、跨域资源共享(CORS)
3、nginx代理跨域
4、nodejs中间件代理跨域
5、document.domain+ iframe跨域
6、location.hash + iframe跨域
7、window.name + iframe跨域
8、postMessage跨域
9、WebSocket协议跨域
47、Vue组件之间的通信方式都有哪些?
- 父子组件之间的通信
- 兄弟组件之间的通信
- 祖孙与后代组件之间的通信
- 非关系组件间之间的通信
小结
- 父子关系的组件数据传递选择props与 $ emit进行传递,也可以选择ref
- 兄弟关系的组件数据传递选择$ bus,其次可以选择$parent进行传递。
- 祖先与后代组件数据传递可选择attrs与listeners或者 Provide与 Inject
- 复杂关系的组件数据传递可以通过vuex存放共享的变量
48、VUE路由的原理?
49、React 性能优化的手段有哪些
- 避免使用内联函数
- 使用React.Fragment避免额外标记添加DOM
- 使用immutable
- 懒加载组件
- 事件绑定方式
- 服务端渲染
- 使用React.Memo来缓存组件
- 使用useMemo缓存大量的计算
- 使用React.PureComponent,shouldComponentUpdate
- 避免使用匿名函数
- 延迟加载不是立即需要的组件
- 调整CSS而不是强制组件加载和卸载
- 唯一的标识
50、简述在浏览器中输入url地址 到浏览器呈现出页面发生的整个过程
- 首先,在浏览器地址栏种输入url
- 浏览器先查看浏览器缓存、路由器缓存、如果缓存中有,会直接在屏幕中显示页面内容。若没有,则跳转到第三步。
- 在发送http请求前,需要域名解析(DNS解析),解析获取相应的IP地址。
- 浏览器向服务器发起tcp连接,与浏览器tcp三次握手。
- 握手成功后,浏览器向服务器发送http请求,请求数据包。
- 服务器处理收到的请求,将数据返回至浏览器。
- 浏览器收到HTTP响应。
- 读取页面内容,浏览器渲染,解析html源码。
- 生成DOM树,解析css样式,js交互。
- 客户端和服务器交互
- ajax查询
51、SPA首屏加载速度慢的怎么解决
首屏时间,指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容。
加载慢的原因:
- 网络延时问题
- 资源文件体积是否过大
- 资源是否重复发送请求去加载了
- 加载脚本的时候,渲染内容堵塞了
解决方案:
- 减小入口文件积
- 静态资源本地缓存
- UI框架按需加载
- 图片资源的压缩
- 组件重复打包
- 开启GZip压缩
- 使用SSR
52、说说你对webSocket的理解
WebSocket是HTML5提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接
并进行双向数据传输。
WebSocket 的出现就解决了半双工通信的弊端。它最大的特点是:服务器可以向客户端主动推动消息,客户端也可以主动向服务器推送消息。
概括地说就是:支持双向通信,更灵活,更高效,可扩展性更好
- 支持双向通信,实时性更强
- 可以发送文本,也可以发送二进制数据
- 建立在TCP协议之上,服务端的实现比较容易
- 数据格式比较轻量,性能开销小,通信高效
- 没有同源限制,客户端可以与任意服务器通信
- 协议标识符是ws(如果加密,则为wss),服务器网址就是Url。
- 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP
代理服务器。
53、说说如何借助webpack来优化前端性能
一般项目在完成后,会通过webpack进行打包,利用webpack对前端项目性能优化是一个十分重要的环节。
Webpack是一个模块打包工具,可以使用webpack管理模块,并分析模块间的依赖关系最终编译输出模块为html、JavaScript和css以及各种静态文件,让开发更加的高效。
如何优化:
- Js代码的压缩
- CSS代码压缩
- HTML文件代码的压缩
- 文件大小的压缩
- 图片压缩
- Tree Shaking
- 代码分离
- 内联chunk
总结: 关于webpack对前端性能的优化,可以通过文件体积大小入手,其次还可通过分包的形式、减少http请求次数等方式,实现对前端性能的优化
54、AMD、CMD、commonJS模块化规范的区别?
这三个都是为Js模块化加载而生的,使模块能够按需加载,使系统同庞杂的代码得到组织和管理。模块化的管理代码使多人开发得到了更好的合作。
CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。
AMD规范则是非同步加载模块,允许指定回调函数。
CMD是需要的时候去请求,而不是先加载再使用。RequireJS用的就是AMD,AMD用define定义方法,用require引用模块
55、说说Connect组件的原理是什么?
connect是高阶组件,接受两个方法,返回的函数接收参数是组件,从而返回一个新的组件。
如下:
connect([mapStateToProps], [mapDispatchToProps])(component)
connect工作流程
Provider组件,在原应用组件上包裹一层,使原来整个应用成为Provider的子组件
接收Redux的store作为props,通过context对象传递给子孙组件上的connect
它真正连接 Redux 和 React,它包在我们的容器组件的外一层,它接收上面 Provider 提供的 store 里面的 state 和 dispatch,传给一个构造函数,返回一个对象,以属性形式传给我们的容器组件
connect 的作用
connect作用是让你把组件和store连接起来,产生一个新的组件(connect 是高阶组件)
56、说说你对受控组件和非受控组件的理解?应用场景?
受控组件
由React控制的输入表单元素而改变其值的方式,称为受控组件。
比如,给表单元素input绑定一个onChange事件,当input状态发生变化时就会触发onChange事件,从而更新组件的state。
非受控组件
非受控组件指的是,表单数据由DOM本身处理。即不受setState()的控制,与传统的HTML表单输入相似,input输入值即显示最新值。
在非受控组件中,可以使用一个ref来从DOM获得表单值。
57、说说package.json中版本号的规则
第一部分为主版本号,变化了表示有了一个不兼容上个版本的大更改
第二部分为次版本号,变化了表示增加了新功能,并且可以向后兼容
第三部分为修订版本号,变化了表示 有bug修复,并且可以向后兼容
第四部分为日期版本号加希腊字母版本号,希腊字母版本号共有五种,分别为base、alpha、 bela 、RCrelease。
58、说说你对koa中洋葱模型的理解?
Koa是一个精简的node框架,被认为是第二代Node框架,其最大的特点就是独特的中间件流程控制,是一个典型的洋葱模型,它的核心工作包括下面两个方面:
- 1.将node原生的req和res封装成为一个context对象
- 2.基于async/await的中间件洋葱模型机制
Koa的洋葱模型是以next()函数为分割点,先由外到内执行Request的逻辑,然后再由内到外执行Response的逻辑,这里的request的逻辑,我们可以理解为是next之前的内容,response的逻辑是next函数之后的内容,也可以说每一个中间件都有两次处理时机。洋葱模型的核心原理主要是借助compose方法。
59、 如果需要手动写动画,你认为最小时间间隔是多久,为什么?
多数显示器默认频率是60Hz,即1秒刷新60次,所以理论上最小间隔为1/60*1000ms = 16.7ms。
为了浏览器的渲染和用户体验的话,最小设置0.1-0.3s最佳。
60、 介绍一下你对浏览器内核的理解?
浏览器内核主要分成两部分: 渲染引擎(layout engineer或Rendering Engine)和JS引擎。
渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。
JS引擎: 解析和执行javascript来实现网页的动态效果。
61、大文件如何做断点续传?
上传大文件时,像服务器处理数据的能力、请求超时、网络波动都会影响我们的用户体验。
可以使用分片上传和断点续传两个概念做处理操作。
分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块来进行分片上传,上传完成之后再由服务器对所有上传的文件进行汇总整合成原始的文件。
断点续传指的是在下载或者是上传时,将下载或者上传任务人为的划分为几个部分。每一个部分采用一个线程进行上传或者下载,如果碰到网络故障,可以从已经上传或者下载的部分开始继续上传或者下载未完成的部分,而没有必要从开头开始上传或者下载,用户可以节省时间,提高速度。
上传过程中将文件在服务器写为临时文件,等全部写完了,将此临时文件重命名为正式文件即可。
62、说说javascript内存泄漏的几种情况?
-
意外的全局变量
一个未声明变量的引用会在全局对象中创建一个新的变量。
-
闭包引起的内存泄漏
闭包可以使变量常驻内存,但如果使用不当就会在成内存泄漏
-
DOM之外的引用
-
被遗漏的定时器和回调函数
-
反复重写同一个属性会造成内存大量占用。(关闭IE后内存会被释放)
怎么避免内存泄漏?
怎么避免内存泄漏
1)减少不必要的全局变量,或者生命周期
较长的对象,及时对无用的数据进行垃圾回收;
2)注意程序逻辑,避免“死循环”之类的 ;
3)避免创建过多的对象 原则:不用了的东西要及时归还。
63、谈谈你对BFC的理解?
BFC 即块级格式上下文。
BFC是Web页面的可视CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。
BFC是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。
BFC的作用?
-
可以实现三栏或者两栏自适应布局
-
可以避免margin重叠问题
-
可以避免高度塌陷
创建BFC的方式?
- 绝对定位元素
- 行内块元素
- overflow的值不为visible
64、说出三种前端清除浮动的方法
(1)、父级div定义height
(2)、最后一个浮动元素后加空div标签 并添加样式clear:both。
(3)、包含浮动元素的父标签添加样式overflow为hidden或auto。
(4)、父级div定义zoom
65、什么是强缓存和协商缓存
强缓存是根据返回头中的 Expires 或者 Cache-Control 两个字段来控制的,都是表示资源的缓存有效时间。
协商缓存是由服务器来确定缓存资源是否可用。
强缓存和协商缓存的区别?
如果浏览器命中强缓存,则不需要给服务器发请求;而协商缓存最终由服务器来决定是否使用缓存,即客户端与服务器之间存在一次通信。
在 chrome 中强缓存(虽然没有发出真实的 http 请求)的请求状态码返回是 200 (fromcache);而协商缓存如果命中走缓存的话,请求的状态码是 304 (not modified)。 不同浏览器的策略不同,在
FireFox中,from cache 状态码是 304.
66、说说git常用的命令有哪些?
- git init 把目录变成一个git仓库
- git status 查看当前版本控制的文件的状态
- git add 文件名 或者 git add . 把文件添加到本地仓库
- git commit -m “操作的描述” 把文件从暂存区提交到本地仓库
- git log 查看版本信息
- git reset --hard “版本号”
- git branch 分支名称 创建分支
- git branch -a 查看分支
- git checkout “要切换的分支名称”
- git merge “要合并过来的分支名称”
- git diff 查看上次修改的状态
- git rm “文件名称”
67、说说你对git rebase 和git merge的理解?区别?
两者都有相同的作用,都是将一个分支的提交合并到另一个分支上
git merge 是将当前分支合并到指定分支
git rebase 是将当前分支移值到指定分支或者指定commit之上
区别:
merge:是通过合并分支会新增一个merge commit。然后将两个分支的历史联系起来,其实是一种非破坏的操作,对现有分支不会以任何方式被更改,但是会导致历史记录相对复杂
rebase:会将整个分支移动到另一个分支上,有效的整合了所有分支上的提交,主要的好处是历史记录更加清晰,是在原有提交的基础上将差异内容反映进去,消除了git merge所需的不必要的合并提交。
68、说说你对栈、队列的理解?应用场景?
栈(stack)又名堆栈,它是一种运算受限的线性表,限定仅在表尾进行插入和删除操作的线性表,表尾这一端被称为栈顶,相反地另一端被称为栈底,向栈顶插入元素被称为进栈、入栈、压栈,从栈顶删除元素又称作出栈,被称为先进后出。
队列:跟栈十分相似,队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头,当队列中没有元素时,称为空队列。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出
栈应用场景:借助栈的先进后出的特性,可以简单实现一个逆序数处的功能,首先把所有元素依次入栈,然后把所有元素出栈并输出
队列应用场景:当我们需要按照一定的顺序来处理数据,而该数据的数据量在不断地变化的时候,则需要队列来帮助解题;队列的使用广泛应用在广度优先搜索种,例如层次遍历一个二叉树的节点值(后续将到)
69、说说TCP为什么需要三次握手和四次挥手?
三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。
主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。
四次挥手指的是在tcp终止一个连接时,需要四次挥手,当服务器在收到客户端的断开请求报文后,并不会立即关闭连接,而是先接受一个收到关闭连接的请求,当服务器的所有请求报文发送完毕之后,才能断开连接。
70、原生js如何实现上拉加载下拉刷新?
上拉加载的本质是页面触底,或者快要触底时的动作
scrollTop:滚动视窗的高度距离window顶部的距离,它会随着往上滚动而不断增加,初始值是0,它是一个变化的值
clientHeight:它是一个定值,表示屏幕可视区域的高度
scrollHeight:页面不能滚动时是不存在的,body长度超过window时才会出现,所表示body所有元素的长度
简单实现
let clientHeight = document.documentElement.clientHeight; //浏览器高度
let scrollHeight = document.body.scrollHeight;
let scrollTop = document.documentElement.scrollTop;
let distance = 50; //距离视窗还用50的时候,开始触发;
if ((scrollTop + clientHeight) >= (scrollHeight - distance)) {
console.log(“开始加载数据”);
}
下拉刷新的本质是页面本身置于顶部时,用户下拉时需要触发的动作
监听原生touchstart事件,记录其初始位置的值,e.touches[0].pageY
监听原生touchmove事件,记录并计算当前滑动的位置值与初始位置值的差值,大于0表示向下拉动,并借助CSS3的translateY属性使元素跟随手势向下滑动对应的差值,同时也应设置一个允许滑动的最大值
监听原生touchend事件,若此时元素滑动达到最大值,则触发callback,同时将translateY重设为0,元素回到初始位置
71、说说你对事件循环的理解?
JavaScript 在设计之初便是单线程,即指程序运行时,只有一个线程存在,同一时间只能做一件事
为了解决单线程运行阻塞问题,JavaScript用到了计算机系统的一种运行机制,这种机制就叫做事件循环。
同步任务进入主线程,异步进入任务队列,等主线程任务执行完,异步任务再推入主线程执行,这就是事件循环。
72、说说设备像素、css像素、设备独立像素、dpr、ppi之间的区别
CSS像素(css pixel, px): 适用于web编程,在 CSS 中以 px 为后缀,是一个长度单位
设备像素(device pixels),又称为物理像素;指设备能控制显示的最小物理单位,不一定是一个小正方形区块,也没有标准的宽高,只是用于显示丰富色彩的一个“点”而已
设备独立像素(Device Independent Pixel):与设备无关的逻辑像素,代表可以通过程序控制使用的虚拟像素,是一个总体概念,包括了CSS像素
dpr(device pixel ratio),设备像素比,代表设备独立像素到设备像素的转换关系,在JavaScript中可以通过 window.devicePixelRatio 获取
ppi (pixel per inch),每英寸像素,表示每英寸所包含的像素点数目,更确切的说法应该是像素密度。数值越高,说明屏幕能以更高密度显示图像
73、React render方法的原理,在什么时候会触发?
首先,render函数在react中有两种形式,在类组件中,指的是render方法,在函数组件中,指的是函数组件本身。
在render过程中,通常会编写jsx代码,会通过babel进行转换成我们熟悉的jsx代码,转换成createElement这种形式,用于生成虚拟DOM,最终转换成真实DOM。react将新调用的render函数返回的树与旧版本的树进行比较,这一步是决定如何更新DOM的必要步骤,然后进行diff比较,更新DOM树。
什么时候触发?
- 在react中,类组件只要执行了setState方法,就一定会触发render函数执行,函数组件使用useState更新状态不一定导致重新render。
- 组件的props 改变了,不一定触发 render 函数的执行,但是如果 props 的值来自于父组件或者祖先组件的 state。
- 在这种情况下,父组件或者祖先组件的 state 发生了改变,就会导致子组件的重新渲染。所以,一旦执行了setState就会执行render方法,useState会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染
74、说说你对vue中mixin的理解?
mixin是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类。
mixin是一种类,在vue中就是js文件,主要的作用是作为功能模块引用。 因为在项目中,可能不同组件会有相同的功能
比如控制元素的显示和隐藏,如果他们的变量和规则也完全相同的话,就可以把这个功能单独提取出来,放在mixin.js中,再引入,就可以实现一样的功能了。
引入的方法也分为全局混入和局部混入,局部混入就是在每个组件中引入,全局混入就是在main.js中通过Vue.mixin()引入。
75、说说Real diff算法是怎么运作的?
Diff算法的目的就是为了找到哪些节点发生了变化,哪些没有发生变化,可以复用,具体实现就是进行虚拟dom对比,返回一个patch对象用来存储两个节点不同的地方,最后用patch记录的消息去局部的更新dom,diff算法比较只会在同层级下进行,不会跨层级去比较。
跟Vue一致,React通过引入Virtual DOM的概念,极大地避免无效的Dom操作,使我们的页面的构建效率得到了极大的提升。
而diff算法就是更高效地通过对比新旧Virtual DOM来找出真正的Dom变化之处。
diff算法主要遵循三个层级的策略:
- Tree层:是对dom节点的跨层级移动的操作忽略不计,只对相同层级的dom进行比较,一旦发现这个节点不存在,会删除该节点以及该节点以下的所有子节点。
- Component层
- 1) 遇到同一类型的组件时,会遵循tree diff ,进行层次对比
- 2) 遇到不同类型的组件时,直接将这个不同的组件判断为脏组件,并替换该节点以及该节点以下的所有子节点
- 3) 在同一类型的两个组件时,当知道这个组件的虚拟dom没有发生变化时,可以手动使用shouldcomponentupdata()来判断组件是否需要进行diff,提高了diff的性能和效率
- Element层:是对同一层级的dom节点进行比较:分为三种情况
- 1) 面对全新的节点时,执行插入操作
- 2) 面对多余的节点时,执行删除操作
- 3) 面对换位的节点时,执行移动操作
76、说说你对redux中间件的理解?常用的中间件有哪些?实现原理?
Redux中,中间件就是放在dispatch过程,在分布action进行拦截处理。当action发出之后,reducer立即算出state,整个过程是一个同步的操作,如果需要异步操作,就需要中间件的支持。
常用redux中间件:
Redux-thunk : 用于异步操作
Redux-promise : 用于异步操作
Redux-logger : 用于日志记录
中间件都需要通过applyMiddleWares进行注册,作用是将所有的中间件组成一个数组,一次执行,然后作为第二个参数传入到createStore中。
77、说说React生命周期中有哪些坑?如何避免?
getDerivedStateFromProps 容易编写反模式代码,使受控组件与非受控组件区分模糊。
componentWillMount 在 React中已被标记弃用,不推荐使用,主要原因是新的异步渲染架构会导致它被多次调用。所以网络请求及事件绑定代码应移至componentDidMount中。
componentWillReceiveProps 同样被标记弃用,被 getDerivedStateFromProps 所取代,主要原因是性能问题。
shouldComponentUpdate 通过返回 true 或者 false 来确定是否需要触发新的渲染。主要用于性能优化。
componentWillUpdate 同样是由于新的异步渲染机制,而被标记废弃,不推荐使用,原先的逻辑可结合getSnapshotBeforeUpdate 与
componentDidUpdate 改造使用。
如果在 componentWillUnmount 函数中忘记解除事件绑定,取消定时器等清理操作,容易引发 bug。
如果没有添加错误边界处理,当渲染发生异常时,用户将会看到一个无法操作的白屏,所以一定要添加。
如何避免:
- 在不恰当的时机调用了不合适的代码
- 在需要调用的时候,没有调用
78、调和阶段setState干了什么?
- 代码中调用 setState函数之后,React会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。
- 经过调和过程,React会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面;
- 在 React 得到元素树之后,React会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染;
- 在差异计算算法中,React能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。
79、 说说redux的实现原理是什么,写出核心代码?
redux三大基本原则是:
- 单一数据源
- state是只读的
- 使用纯函数来执行修改
注意的是,redux并不是只应用在react中,还与其他界面库一起使用,如Vue
实现原理:
redux要求我们把数据都放在store公共存储空间,一个组件改变了store里的数据内容,其他组件就能感知到store的变化,再来取数据,从而实现了一个数据传递的功能。
转换为代码是,React Components 需要获取一些数据, 然后它就告知 Store 需要获取数据,这就是就是 Action Creactor , Store 接收到之后去 Reducer 查一下, Reducer 会告诉 Store 应该给这个组件什么数据。
80、React合成事件的原理?
React 合成事件(SyntheticEvent)是 React 模拟原生 DOM 事件所有能力的一个事件对象,即浏览器原生事件的跨浏览器包装器。它根据 W3C 规范 来定义合成事件,兼容所有浏览器,拥有与浏览器原生事件相同的接口。
在 React 中,所有事件都是合成的,不是原生 DOM 事件,但可以通过 e.nativeEvent 属性获取 DOM 事件。
有合成事件的好处?
- 进行浏览器兼容,实现更好的跨平台
- 避免垃圾回收
- 方便事件统一管理和事务机制
React合成事件的工作原理大致可以分为两个阶段:
- 事件绑定
- 事件触发
81、为什么react元素有一个$$type属性?
因为json不支持symbol类型,所以用户即使提交了message的信息,到最后服务器端也不会保存
typeof 的属性,而在渲染的时候, react 会检测是否有 typeof的属性,如果没有这个属性则会拒绝处理该元素
$$typeof 是为了防止 XSS 攻击。
使用 Symbol 类型是因为 JSON 中无法传递 Symbol。React 会检查 element.$$typeof 然后拒绝处理非法的元素。
82、说说你对fiber架构的理解?解决了什么问题?
- 为每个增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务
- 增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行
- dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行
从架构角度来看,Fiber 是对 React核心算法(即调和过程)的重写
从编码角度来看,Fiber是 React内部所定义的一种数据结构,它是 Fiber树结构的节点单位,也就是 React 16 新架构下的虚拟DOM。
解决了什么问题?
Fiber 把一个渲染任务分解为多个渲染任务,而不是一次性完成,把每一个分割得很细的任务视作一个"执行单元",React 就会检查现在还剩多少时间,如果没有时间就将控制权让出去,故任务会被分散到多个帧里面,中间可以返回至主进程控制执行其他任务,最终实现更流畅的用户体验。
83、说说你对事件循环event loop的理解?
Event Loop即事件循环,是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
JavaScript是一门单线程的语言,意味着同一时间内只能做一件事情,但是并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环。
所有的任务都分为同步任务、异步任务。
同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
异步任务:ajax网络请求、setTimeout定时器函数。
同步任务进⼊主线程,即主执⾏栈,异步任务进⼊任务队列,主线程内的任务执 ⾏完毕为空,会去任务队列读取对应的任务,推⼊主线程执⾏。那么上述过程的不断重复就称为事件循环
84、数组常用方法及作用,至少15个?
- push():向数组的尾部新增一个或者多个元素
- unshift():向数组的头部新增一个或者多个元素
- pop():从数组的尾部删除元素
- shift():从数组的头部删除元素
- splice():可以对数组进行新增或者删除
- sort():排序
- reverse():倒序
- concat():合并数组
- join():将数组转换为字符串
- slice():数组的截取
- forEach():循环
- some(): 需要数组一项满足条件则返回true,只要有一项是满足的就返回true
- every():需要数组每一项都满足条件则返回true
- map():返回计算后的元素组成的新数组
- filter():返回满足条件的元素组成新的数组
- Array.isArray( ):检查是否为数组
85、for…in循环和for…of循环的区别?
- for…of 遍历获取的是对象的键值,for…in 获取的是对象的键名
- for… in 会遍历对象的整个原型链,性能非常差不推荐使用,而 for … of 只遍历当前对象不会遍历原型链for…in循环和for…of循环的区别?
- 对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值;
总结: for…in 循环主要是为了遍历对象而生,不适用于遍历数组;
for…of 循环可以用来遍历数组、类数组对象,字符串、Set、Map 以及 Generator 对象。
86、Js数据类型判断都有哪几种方式?至少说出5种?它们的区别是什么?
-
instanceof
-
Array.isArray
-
Object.prototype.isPrototypeOf 【object原型上的方法】
-
Object.getPrototypeOf
-
Object.prototype.toString
-
typeof判断
-
===(严格运算符)
不同点:
typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型。 返回值是一个字符串,该字符串说明运算数的类型。
typeof 一般只能返回如下几个结果:number,boolean,string,function,object,undefined。
instanceof 用于判断一个变量是否某个对象的实例,如 var a=new Array();alert(a instanceof Array); 会返回 true,同时 alert(a instanceof Object) 也会返回 true;这是因为 Array 是 object 的子类。
87、说说你对Object.defineProperty()的理解?
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
该方法接受三个参数 :
-
第一个参数是 obj:要定义属性的对象。
-
第二个参数是 prop:要定义或修改的属性的名称或 Symbol。
-
第三个参数是 descriptor:要定义或修改的属性描述符。
const obj = {}; Object.defineProperty(obj, "property", { value: 18 }); console.log(obj.property); // 18
88、说说react中onClick绑定后的工作原理?
1、首先react有自己的事件系统,也是遵循w3c的,这个事件系统的名称叫做合成事件。而自定义事件系统的动机只要包含一下几个方面:
抹平不同浏览器之间的兼容性差异。最主要的动机。
件合成既可以处理兼容性问题
提供一个抽象的跨平台事件机制
可以做更多优化
可以干预事件的分发
2、当给组件(元素)绑定onClick事件之后
react会对事件先进行注册,将事件统一注册到document上
根据组件唯一的标识key来对事件函数进行存储
3、统一的指定dispatchEvent回调函数
4、 储存事件回调
react会将click这个事件统一存到一个对象中,回调函数的存储采用键值对(key/value)的方式存储在对象中,key 是组件的唯一标识 id,value 对应的就是事件的回调函数,通过组件的key就能回调到相应的函数了
89、react中setState和replaceState的区别?
setState:更新状态
replaceState:替换状态
setState用于设置状态对象的
setState(object nextState[, function callback])
nextState,将要设置的新状态,该状态会和当前的state合并
callback,可选参数,回调函数,该函数会在setState设置成功,且组件重新渲染后调用。
合并nextState和当前state,并重新渲染组件。setState是React事件处理函数中和请求回调函数中触发UI更新的主要方法。
replaceState()方法与setState()类似,但是方法只会保留nextState中状态,原state不在nextState中的状态都会被删除。
90、说说你对useEffect的理解,可以模拟哪些生命周期?
- 默认函数组件没有生命周期
- 函数组件是一个纯函数,执行完即销毁,自己无法实现生命周期
- 通过Effect hook把生命周期“钩”到纯函数中
模拟componentDidMount - useEffect 依赖 [ ] 模拟compenentDidUpdate -
useEffect 无依赖 ,或者 依赖 [a,b,c] 模拟componentWillUnMount - useEffect
中返回一个函数
整理的不是很全,如有错误,请各位大佬多多指教~~,及时更正~~~