React
说说对 React 的理解?有哪些特性?
React是一个用于构建用户界面的JavaScript库。
特点:
- 通过对DOM的模拟,最大程度的减少与DOM的交互
- 可以和已知的库很好的配合
- jsx语法
- 组件化
- 单项响应的数据流
说说 Real DOM 和 Virtual DOM 的区别?优缺点?
区别:
Real DOM是浏览器的真实DOM
virtual DOM是JavaScript对象
优缺点:
Real DOM的优点:浏览器的原生DOM,可以直接操作
Real DOM的缺点:当DOM结构发生改变时,浏览器需要重新布局。损耗性能
virtual DOM的优点:避免了不必要的DOM操作,提升了性能
virtual DOM的缺点:首次渲染计算量大,需要计算virtual DOM的差异
说说React Jsx转换成真实DOM过程?
React中的JSX是一种语法=糖,它可以让我们在JavaScript中编写类似HTML的代码。当我们在React中使用JSX时,它会被转换成真实的DOM元素。这个过程是由Babel编译器完成的。
Babel编译器 会将JSX转换成React.createElement()函数的调用,然后React根据这个函数的返回值来创建真实的DOM元素。
说说你第mvc和mvvm的理解
MVC是model view controller的缩写
model表示模型层用于存储数据和处理逻辑、view视图层用于用户页面、controller控制器用于用户操作页面是来修改model中的数据
MVVM是model view viewmodel的缩写
model表示模型层用于存储数据和处理逻辑、view视图层用于用户页面、viewmodel视图模型用于model和view层的关联
说说react中引入css的方式有哪几种?区别?
内联样式
<div style={{color:''}}></div>
使用模块化css
// css文件命名 xxx.module.css // 引入 import styles from '路径/xxx.module.css' <div className={styles['类名']}></div>
使用link标签全局设置样式
<link rel="stylesheet" href="css文件路径"/>
说说对React中合成事件的理解
React中的合成事件是一种更高效和跨浏览器兼容的处理事件的方式。
根据W3C的规范来定义合成事件,具备所有浏览器的兼容,拥有和浏览器相同的事件接口
和原生的JavaScript相比,react中的事件绑定方式不同,通过onClick事件名首字母大写的方式定义合成事件。这种合成事件最后都对被浏览器识别并执行
说说setState的理解
- 在18版本后是一个纯异步函数
- 如果在一个方法中定义多个setState,React会将多个合成一个
- 在同步的代码中是异步的,在异步的代码中
- 参数说明即可
state和props的区别
在react中组件分为有状态组件和无状态组件,state就是在有状态的组件中的动态的数据。
state:state一般定义在constructor生命周期中,定义在state中的数据可以页面变化。state如果修改的话需要使用this.setState方法去修改state中的数据。
props:props用来实现react组件通信功能,react的一大特性就是组件化。而组件间通信就是通过props参数接收
区别:
props是父组件传进来的参数,且参数不可修改
state是定义在类组件中的参数,这个参数可以修改
super()和super(props)的区别
ES6中通过extends关键实现类的继承,在子类中的constructor函数中必须存在super()而且次方法必须先调用,因为子类如果是继承了一个类的情况下,它是没有this的,通过super方法来将父类的this指向子类。
React中的类组件是基于ES6类的规范去实现的,类组件需要继承React.Conponent类,所以一旦有了继承那么必须在constructor中使用super方法才能初始化this,一旦定义了super方法那么就需要写入props参数,这个参数是父组件传递过来的数据。这个props如果不在constructor中通过super方法初始化的情况下,可以在render方法中获取到。但是如果定义了super方法,那么一定要填入props参数,如果不填props参数会报错
react中key的作用
实现DOM元素的唯一性,react渲染页面是通过diff算法操纵虚拟DOM来完成的,diff算法就是将前一次的key和后一次的key做对比,将差异划分后再将虚拟DOM转换为真实DOM并渲染到页面中
Context状态树的执行流程?
context是react提供的一种传递数据的方式。context状态树使用react库中的createContext函数创建,此函数返回两个对象,provider和consumer。
通过createContext创建context对象,context对象中存有两个函数,provider,consumer。单独导出provider和consumer,默认导出context对象。
在根组件中包裹provider组件,类组件使用静态属性来接收数据 static createContext = context,函数组件使用接收数据在consumer中有一个函数,函数中有一个参数参数值就是provider的值
什么是高阶组件,有什么作用?
高阶组件是一个函数,它接收一个组件并返回一个新的组件。它的作用是:代码复用、渲染劫持、条件渲染
react中路由传递参数的方式?
react-router-dom 分为两个版本 5 和 6 。各个版本传参方式和读取参数的方式不同
5
三种方式:路径后 ?键=值、路由(/main/:键)传参(路径后/值)、to={{pathname: ’ 路由 ',state:{ 键 : 值 } }}
三种获取参数分别是:props.location.search \ props.match.params \ props.location.state、
6
三种方式:路径后 ?键=值、路由(/main/:键)传参(路径后/值)、to={{pathname: ’ 路由 ',state:{ 键 : 值 } }}
let [query,setQuery]useSreachParams() query.get(‘键名’) 、useParams().键名、useLocation().state.键名
说说你对SPA的理解?
SPA是单页面开发模式,使用JavaScript框架(Vue,React,Angular)来实现动态的显示页面内容。
react如何捕捉异常
- js方法 try ··· catch
- react生命周期 static getDerivedStateFromError componentDidCatch
- 事件监听 window.addEventListener(‘error’,(err)=>{·····})
说说React中setState和replaceState的区别?
setState和replaceState都是用来修改状态的,只不过有一点区别
setState是拿到前一次的state状态和当前的状态合并,最后返回覆盖state状态
replaceState是直接全覆盖state状态,说白了就是替换掉前一次的state状态。
在多数情况下还是使用setState来修改状态较为完善
说说你对fiber架构的理解?解决了什么问题?
当一个应用程序需要并发来处理多个请求时,那就需要使用线程来处理了,而线程的切换和创建都是会占用系统内部CPU。
而fiber架构是在应用程序内部来处理并发请求,在内部创建多个线程以完成请求。这样能在节省系统CPU的情况下高效的、快速的来处理并发
说说你对redux中间件的理解?常用的中间件有哪些?实现原理?
理解:用来在action和reducer之间拦截,来实现异步、日志、路由跳转等
常用:redux-thunk 处理异步请求、redux-promise使action返回一个promise对象、redux-logger来实现日志,每当state修改了就会记录哪里发生了变化
原理:
import {createStore,applyMiddleware} from 'redux'; import reduxThunk from 'redux-thunk' // 使用applymiddleware函数来创建中间件,将中间件作为参数 const middleware = applyMiddleware(reduxThunk) // reducer是处理dispatch任务,initalState初始化state,参数3为中间件 const store = createStore(reducer, initalState, middleware)
redux中同步action与异步action最大的区别是什么?
同步的action是一个纯函数,而异步的通过Middleware拦截最后通过dispatch派发同步任务
redux-saga和redux-thunk的区别与使用场景?
redux-saga和redux-thunk都是redux中间件。
redux-thunk处理简单的http请求,简单容易上手
redux-saga处理一些复杂的异步逻辑例如websocket、任务取消、多任务并发
在使用redux过程中,如何防止定义的action-type的常量重复?
使用redux-action中的createAction函数来创建action-type的值
import {createAction} from ‘redux-action’ createAction(‘TEST_FIRST’) // 这样定义的使用这种方式生成的action-type名是不会重复的
知道react里面的createPortal么,说说其使用场景?
它是react-dom 中ReactDOM的一个函数
使用场景:在渲染一个弹框或者对话框时。这样可以避免一些样式的冲突。
useEffect的依赖为引用类型如何处理?
将依赖项数组分割为多个基本类型依赖项(如数字或字符串),并将其作为 useEffect 的多个参数。例如:useEffect(() => { … }, [obj.prop1, obj.prop2, arr.length]);
使用 useRef 钩子引用依赖项,然后将其传递给 useEffect。例如:const depRef = useRef(dep); useEffect(() => { … }, [depRef.current]);
在传递对象时,使用 Object.assign 或 spread 运算符创建新的对象。例如:useEffect(() => { … }, [Object.assign({}, obj)]);
什么是强缓存和协商缓存?
强缓存和协议缓存都是用来将后台获取的数据缓存起来减少了和后台的交互,来实现提升加载速度的效果
两者的区别在于强缓存检查本地是否有对应的缓存文件,有则直接使用,没有则通过协议缓存
说说Real diff算法是怎么运作的?
Diff
算法是虚拟DOM
的一个必然结果,它是通过新旧DOM
的对比,将在不更新页面的情况下,将需要内容局部更新Diff
算法遵循深度优先,同层比较的原则- 可以使用
key
值,可以更加准确的找到DOM
节点
react
中diff
算法主要遵循三个层级的策略:
tree层级
conponent 层级
element 层级
tree
层不会做任何修改,如果有不一样,直接删除创建
component
层从父级往子集查找,如果发现不一致,直接删除创建
element
层有key值做比较,如果发现key
值可以复用的话,就会将位置进行移动,如果没有,则执行删除创建
为什么react元素有一个$$type属性?
目的是为了防止
XSS 攻击
。因为Synbol
无法被序列化,所以React
可以通过有没有$$typeof
属性来断出当前的element
对象是从数据库来的还是自己生成的。如果没有$$typeof
这个属性,react
会拒绝处理该元素。
说说你对事件循环event loop的理解?
任务在主线程不断进栈出栈的一个循环过程。
在JavaScript中,所有的任务都可以分为
同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等
异步任务还可以细分为微任务与宏任务
微任务一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前
宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合
React的props.children使用map函数来遍历会收到异常显示,为什么?应该 如何遍历?
如果只有一个子节点时会收到异常显示,因为一个子节点时不是一个数组,不是数组就不能进行使用map函数。
应该使用React中的一个函数Children中的toArray()方法来将单个节点转换成数组类型。转换后就可以遍历了
谈谈你对immutable.js的理解?
Immutable.js是Facebook开发的一个JavaScript库,它提供了一系列的数据结构和方法来帮助我们创建不可变的数据对象。
Immutable.js提供了几种常见的不可变数据结构,比如List、Map、Set等,这些数据结构支持函数式编程范式中的高阶操作,例如map、filter、reduce等用于处理数组的方法,可以让你轻松地对数据进行增、删、查、改等一系列操作。
Immutable.js与React有着天然的结合点。React推崇“单向数据流”,而Immutable.js正好符合这个思路,它可以让我们在React的应用中更加灵活地控制状态树,同时通过使用shouldComponentUpdate生命周期钩子可以帮助我们完成对组件更新的优化。
Vue
说说对vue的理解
vue是一个基于用户页面的JavaScript库
特点:
数据驱动 => MVVM双向数据绑定结构
组件化 => 减少代码复用、提高可维护性
虚拟DOM
指令系统 => vue可以通过v-的前缀来实现一些操作
常用的指令有
v-if 条件渲染
v-show 控制隐藏
v-on 绑定事件 @简写
v-for 循环渲染
v-bind 属性绑定 :简写
v-model 双向数据绑定
Vue和react的相同和不同
相同点:
组件化操作
虚拟DOM
不同点:
react数据驱动为MVC单项数据流,vue为MVVM双向数据流
react diff算法是计算差异后统一更新,vue是边计算差异,边更新
webpack
说说如何借助webpack来优化前端性能?
代码分隔(实现按需加载)、压缩代码(减少文件大小)、静态资源处理(file-loader和url-loader)、懒加载和按需加载
说说webpack中常见的loader?解决了什么问题?
babel-loader:将ES6/ES7/JSX装换为ES5语法,以便浏览器识别
css-loader:解析CSS文件,将css文件装换为模块以便JavaScript使用
style-loader:用于将CSS样式注入DOM中
file-loader:用于图片、静态文件,转换为URL
url-loader:将文件转换为base64格式
sass-loader:用于将sass/scss装换为CSS
less-loader:用于将LESS装换为CSS
说说webpack中代码分割如何实现?
使用 entry 配置,根据入口进行代码拆分。
配置 splitChunks 插件,根据不同的策略、依据模块之间的关系将公共部分抽离成单一文件,如 vendor 外部依赖、公共代码等。
在开发中可以根据实际需求选择不同的方案,以达到更高的性能和优化效果。同时,为了避免缓存问题,可以在打包时加上输出文件的 chunk hash 值。
JavaScript
JavaScript中的数据类型?存储上的区别?
- 基本数据类型
- 引用数据类型
基本数据类型有
- Number
- String
- Boolean
- Null
- undefind
- symbol
引用数据类型
- object
- Array
- Function
存储方式的区别是:
基本数据类型存储在栈中,而引用数据类型的对象存储在堆中
当将一个基本数据类类型赋值给一个变量时,当前赋值的内存地址是另外开辟了一份,和赋值之前的内存地址不同。
当将一个引用数据类型赋值给一个变量时,因为引用数据类型的值是指向堆中的一个内存地址,那么在赋值之后会将新的变量的内存地址指向那个内存地址
JS内存泄漏的几种情况
全局变量
在JS中,全局变量会一直存在于内存中,直到页面关闭。如果不小心创建了一个全局变量,而且没有及时清除它,就会导致内存泄漏。为了避免这种情况,应该尽量避免使用全局变量,而是使用局部变量。
闭包
闭包是指一个函数可以访问另一个函数内部的变量。如果一个函数返回了一个闭包,而且这个闭包中包含了一些不再需要的变量,那么这些变量就会一直存在于内存中,导致内存泄漏。为了避免这种情况,应该尽量避免使用闭包,而是使用其他方式实现相同的功能。
定时器
定时器是一种常见的JS功能,但是如果不小心使用了错误的方式创建定时器,就会导致内存泄漏。例如,如果使用了setInterval函数而没有及时清除它,就会导致定时器一直存在于内存中,导致内存泄漏。为了避免这种情况,应该使用setTimeout函数,并在定时器执行完毕后及时清除它。
DOM元素
在JS中,DOM元素也会占用内存。如果不小心创建了大量的DOM元素,而且没有及时清除它们,就会导致内存泄漏。为了避免这种情况,应该尽量避免创建大量的DOM元素,而是使用其他方式实现相同的功能。
如何通过原生js实现一个节流函数和防抖函数,写出核心代码,不是简单的思路?
节流函数和防抖函数都是为了防止一个事件频繁触发而设计的,但是具体的实现方法有些不同
节流函数是指在一段时间内只能执行一次函数,如果在执行函数期间触发函数,则不会调用
function(fn,time){
let timer;
if(!time){ // time为false时才会触发函数体
timer = setTimeout(()=>{
fn()
timer = null
},time)
}
}
防抖函数是指延迟执行函数,比如延迟一秒执行。如果在执行期间再次触发该函数会停止上一次的函数,并运行本次的函数
function(fn,time){
let timer;
clearTimeout(timer)//先清理后执行,这样在执行中的函数会被清理掉并执行新的函数
timer = setTimeout(()=>{
fn()
},time)
}
for…in循环和for…of循环的区别?
- 遍历对象属性:for…in循环可以遍历一个对象的所有可枚举属性(包括自有属性和继承属性),而for…of循环不可以遍历对象属性。
- 遍历数组下标或元素:for…in循环通过对象键名遍历数组下标或者对象属性,而for…of循环则通过数组元素值遍历数组。可以看出,如果我们使用for…in循环遍历数组时,可能会得到意外结果,比如输出“length”这个键名。
- 遍历顺序:for…in 循环是无序的,而for…of循环是有序的。
Js数据类型判断都有哪几种方式?至少说出5种?它们的区别是什么?
在JavaScript中,数据类型判断有以下几种方式:
- typeof操作符:可以返回一个字符串,表示当前值的类型。它可以用来判断基本数据类型(除了null),以及函数、对象等引用类型。如typeof 123将返回"number"。
- instanceof操作符:可以检测当前实例是否是指定类型的实例,可以用来判断自定义的复杂数据类型和内置的引用类型。如[1,2,3] instanceof Array将返回true。
- Object.prototype.toString.call方法:可以判断基本数据类型、引用类型、以及内置对象类型。它返回的是"[object XXX]“,其中XXX代表当前值的类型。如Object.prototype.toString.call(“hello”)将返回”[object String]"。
- constructor属性:可以获取当前对象的构造函数,从而进行类型判断。如"abc".constructor === String将返回true。
- isArray方法:可以判断当前值是否为数组,仅适用于判断数组类型。如Array.isArray([1,2,3])将返回true。
这些方式均可用于数据类型的判断,但其使用场景、返回结果、效率等方面略有差别。其中,typeof操作符是最常见的类型判断方式,但对于某些类型(如null)返回的结果不够准确;instanceof操作符适用于复杂数据类型的判断,但只能精确地判断是否是某个类的实例;Object.prototype.toString.call方法适用范围比较广泛,但返回结果需要手动解析;constructor属性只适用于判断对象类型,并且有可能被改变;isArray方法则仅适用于数组的判断,但是由于其专门针对数组做了优化,具有较高的性能。
说说你对Object.defineProperty()的理解?
Object.defineProperty()方法是JavaScript中常用的一个对象定义方法,主要作用是定义对象的属性。通过该方法可以为一个对象添加新的属性
Object.defineProperty(obj, prop, descriptor)
参数obj代表需要定义属性的对象,参数prop代表属性名,参数descriptor是表示该属性的描述符对象。描述符对象有两种类型:
- 数据描述符:用于定义数据属性的特性,包括value(属性的值)、writable(是否可写)、enumerable(是否可枚举)、configurable(是否可配置)。
- 存取描述符:用于定义访问器属性的特性,包括get和set方法(获取和设置属性值的函数)、enumerable、configurable。
const person = {}// 空对象 // 添加数据描述符 Object.defineProperty(person, 'name', { value: 'Alice', writable: false, enumerable: true, configurable: false }) // 添加访问器描述符 let ageVal = 25 Object.defineProperty(person, 'age', { get() { return ageVal }, set(value) { if (typeof value !== 'number') { throw new TypeError('Age must be a number') } ageVal = value }, enumerable: true, configurable: false }) console.log(person.name) // 输出: Alice console.log(person.age) // 输出: 25 person.age = 30 // 设置属性值为30 console.log(person.age) // 输出: 30 person.age = 'thirty' // 抛出错误:Age must be a number
说说AMD、CMD、commonJS模块化规范的区别?
AMD(Asynchronous Module Definition):异步模块定义。AMD采用异步加载方式,在多个模块之间并行加载,可以有效避免页面等待和阻塞,提高性能。主要实现机制是通过define函数来定义一个模块,依赖关系通过回调函数参数声明,并且使用require函数进行加载。范例:
复制代码define(['a', 'b'], function(a, b) { // 模块代码 });
CMD(Common Module Definition):通用模块定义。CMD跟AMD很相似,也是异步加载模块,但它采用了就近依赖方式,而不是预先声明依赖关系,这样使得代码更加简洁清晰;此外,CMD支持延迟执行,只有在真正需要时才加载某个模块。主要实现方式是通过define和require两个函数来实现模块化。例如:
复制代码define(function(require, exports, module) { var a = require('./a'); a.doSomething(); // 模块代码 });
CommonJS:npm的模块规范,JavaScript社区一度普及的服务器端模块标准。CommonJS是同步加载模块,采用require方法加载模块,通过module.exports导出模块,主要应用于后端和Node.js环境中。例如:
复制代码// 定义模块 var a = require('./a'); function b() { // 模块代码 }; module.exports = { b: b };
说说package.json中版本号的规则?
版本号是由三个数字组合而成,分别表示主版本号、次版本号和修订号。每升级一个版本,其中的一个或多个数字会有所变化,这样做可以让用户知道新版本带来了哪些变化。符号**“^”、“~”等操作则可以指定版本范围**。
说说你对koa中洋葱模型的理解?
Koa中的洋葱模型是指将一个请求从外到内依次经过多个中间件处理,然后再从内到外依次经过这些中间件处理,最终得到响应的过程。每个中间件负责对请求或响应进行一些操作。整个过程形成了像洋葱一样层层嵌套的结构,因此被称为洋葱模型。
CDN的特点及意义?
- 加速访问速度
- 提高访问稳定性
- 优化带宽利用率
意义:提升用户体验、减轻服务器压力、为企业减少运营成本
![] == ![],![] == [],结果是什么?为什么?
true 和 false
1 [] 转换成布尔值为true ,!取反就是false,所以两个false相比是相等所以返回true
2 左边为false,右边为true。结果自然是false
什么是闭包,应用场景是什么?
闭包就是在一个函数中返回一个函数。例如
function fn1(){ return function fn2(){ console.log(‘触发’) } }
应用场景:模块封装、事件监听、面向对象编程
CSS
谈谈你是如何做移动端适配的?
viewport 设置 <head> 中的 <meta>
CSS单位vh/em/rem
媒体查询 @media 通过当前的宽度来判断字体的大小等
移动端1像素的解决方案?
1px问题是指高分辨率的设备上,由于像素密度过大,出现线条变粗或消失的情况
解决方案有**CSStransform:scale()**来缩放元素尺寸、viewport来进行缩放、JavaScript适配缩放
53.弹性盒中的缩放机制是怎样的
弹性盒中的项目设置flex-grow属性定义项目的放大比例,默认值为0,值越大,放大越厉害,且不支持负值;
而flex-shrink属性定义项目的缩小比例,默认值为1,数值越大,缩小越厉害,同样不支持负值;
如何使用css实现一个三角形
颜色渐变
background: linear-gradient(45deg, red, red 50%, transparent, transparent 50%);
设置边框
div {
width: 0px;
height: 0px;
border-top: 50px solid transparent;
border-bottom: 50px solid deeppink;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
}