这里写自定义目录标题
前端面试题大合集
Vue相关面试题
1.说说你对vue的理解
一.Vue的核心特性
数据驱动(MVVM)
MVVM表示的是 Model-View-ViewModel
Model:模型层,负责处理业务逻辑以及和服务器端进行交互
View:视图层:负责将数据模型转化为UI展示出来,可以简单的理解为HTML页面
ViewModel:视图模型层,用来连接Model和View,是Model和View之间的通信桥梁
组件化
1.什么是组件化一句话来说就是把图形、非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式,在Vue中每一个.vue文件都可以视为一个组件2.组件化的优势
降低整个系统的耦合度,在保持接口不变的情况下,我们可以替换不同的组件快速完成需求,例如输入框,可以替换为日历、时间、范围等组件作具体的实现
调试方便,由于整个系统是通过组件组合起来的,在出现问题的时候,可以用排除法直接移除组件,或者根据报错的组件快速定位问题,之所以能够快速定位,是因为每个组件之间低耦合,职责单一,所以逻辑会比分析整个系统要简单
提高可维护性,由于每个组件的职责单一,并且组件在系统中是被复用的,所以对代码进行优化可获得系统的整体升级
指令系统
解释:指令 (Directives) 是带有 v- 前缀的特殊属性作用:当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
常用的指令
条件渲染指令 v-if
列表渲染指令v-for
属性绑定指令v-bind
事件绑定指令v-on
双向数据绑定指令v-model
没有指令之前我们是怎么做的?是不是先要获取到DOM然后在…干点啥
Vue跟传统开发的区别
没有落地使用场景的革命不是好革命,就以一个高频的应用场景来示意吧注册账号这个需求大家应该很熟悉了,如下
用jquery来实现大概的思路就是选择流程dom对象,点击按钮隐藏当前活动流程dom对象,显示下一流程dom对象如下图(代码就不上了,上了就篇文章就没了…)
用vue来实现,我们知道vue基本不操作dom节点, 双向绑定使dom节点跟视图绑定后,通过修改变量的值控制dom节点的各类属性。所以其实现思路为:视图层使用一变量控制dom节点显示与否,点击按钮则改变该变量,如下图
总结就是:
Vue所有的界面事件,都是只去操作数据的,Jquery操作DOM
Vue所有界面的变动,都是根据数据自动绑定出来的,Jquery操作DOM
Vue和React对比
这里就做几个简单的类比吧,当然没有好坏之分,只是使用场景不同
相同点
都有组件化思想
都支持服务器端渲染
都有Virtual DOM(虚拟dom)
数据驱动视图
都有支持native的方案:Vue的weex、React的React native
都有自己的构建工具:Vue的vue-cli、React的Create React App
#区别
数据流向的不同。react从诞生开始就推崇单向数据流,而Vue是双向数据流
数据变化的实现原理不同。react使用的是不可变数据,而Vue使用的是可变的数据
组件化通信的不同。react中我们通过使用回调函数来进行通信的,而Vue中子组件向父组件传递消息有两种方式:事件和回调函数
diff算法不同。react主要使用diff队列保存需要更新哪些DOM,得到patch树,再统一操作批量更新DOM。Vue 使用双向指针,边对比,边更新DOM
2.v-show和v-if有什么区别?使用场景分别是什么?
v-show与v-if的共同点
我们都知道在 vue 中 v-show 与 v-if 的作用效果是相同的(不含v-else),都能控制元素在页面是否显示
<Model v-show="isShow" />
<Model v-if="isShow" />
当表达式为true的时候,都会占据页面的位置
当表达式都为false时,都不会占据页面位置
v-show与v-if的区别
控制手段不同
编译过程不同
编译条件不同
控制手段:v-show隐藏则是为该元素添加css–display:none,dom元素依旧还在。v-if显示隐藏是将dom元素整个添加或删除
编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换
编译条件:v-if是真正的条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。只有渲染条件为假时,并不做操作,直到为真才渲染
v-show 由false变为true的时候不会触发组件的生命周期
v-if由false变为true的时候,触发组件的beforeCreate、create、beforeMount、mounted钩子,由true变为false的时候触发组件的beforeDestory、destoryed方法
性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;
v-show与v-if原理分析
具体解析流程这里不展开讲,大致流程如下
将模板template转为ast结构的JS对象
用ast得到的JS对象拼装render和staticRenderFns函数
render和staticRenderFns函数被调用后生成虚拟VNODE节点,该节点包含创建DOM节点所需信息
vm.patch函数通过虚拟DOM算法利用VNODE节点创建真实DOM节点
v-show原理
不管初始条件是什么,元素总是会被渲染
我们看一下在vue中是如何实现的
代码很好理解,有transition就执行transition,没有就直接设置display属性
// https://github.com/vuejs/vue-next/blob/3cd30c5245da0733f9eb6f29d220f39c46518162/packages/runtime-dom/src/directives/vShow.ts
export const vShow: ObjectDirective<VShowElement> = {
beforeMount(el, { value }, { transition }) {
el._vod = el.style.display === 'none' ? '' : el.style.display
if (transition && value) {
transition.beforeEnter(el)
} else {
setDisplay(el, value)
}
},
mounted(el, { value }, { transition }) {
if (transition && value) {
transition.enter(el)
}
},
updated(el, { value, oldValue }, { transition }) {
// ...
},
beforeUnmount(el, { value }) {
setDisplay(el, value)
}
}
v-if原理
v-if在实现上比v-show要复杂的多,因为还有else else-if 等条件需要处理,这里我们也只摘抄源码中处理 v-if 的一小部分
返回一个node节点,render函数通过表达式的值来决定是否生成DOM
// https://github.com/vuejs/vue-next/blob/cdc9f336fd/packages/compiler-core/src/transforms/vIf.ts
export const transformIf = createStructuralDirectiveTransform(
/^(if|else|else-if)$/,
(node, dir, context) => {
return processIf(node, dir, context, (ifNode, branch, isRoot) => {
// ...
return () => {
if (isRoot) {
ifNode.codegenNode = createCodegenNodeForBranch(
branch,
key,
context
) as IfConditionalExpression
} else {
// attach this branch's codegen node to the v-if root.
const parentCondition = getParentCondition(ifNode.codegenNode!)
parentCondition.alternate = createCodegenNodeForBranch(
branch,
key + ifNode.branches.length - 1,
context
)
}
}
})
}
)
React相关面试题
1.说说对 React 的理解?有哪些特性?
1.是什么?
React,用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案
遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效
使用虚拟 DOM 来有效地操作 DOM,遵循从高阶组件到低阶组件的单向数据流
帮助我们将界面成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,构成整体页面
react 类组件使用一个名为 render() 的方法或者函数组件return,接收输入的数据并返回需要展示的内容
class HelloMessage extends React.Component {
render() {
return <div>Hello {this.props.name}</div>;
}
}
ReactDOM.render(
<HelloMessage name="Taylor" />,
document.getElementById("hello-example")
);
上述这种类似 XML 形式就是 JSX,最终会被 babel 编译为合法的 JS 语句调用
被传入的数据可在组件中通过 this.props 在 render() 访问
2.特性
React 特性有很多,如:
JSX 语法
单向数据绑定
虚拟 DOM
声明式编程
Component
着重介绍下声明式编程及 Component
3.优势
通过上面的初步了解,可以感受到 React 存在的优势:
高效灵活
声明式的设计,简单使用
组件式开发,提高代码复用率
单向响应的数据流会比双向绑定的更安全,速度更快
4.说说 Real DOM 和 Virtual DOM 的区别?优缺点?
区别
两者的区别如下:
- 虚拟 DOM 不会进行排版与重绘操作,而真实 DOM 会频繁重排与重绘
- 虚拟 DOM 的总损耗是“虚拟 DOM 增删改+真实 DOM 差异增删改+排版与重绘”,真实 DOM 的总损耗是“真实 DOM 完全增删改+排版与重绘”
优缺点
真实 DOM 的优势:
- 易用
缺点:
- 效率低,解析速度慢,内存占用量过高
- 性能差:频繁操作真实 DOM,易于导致重绘与回流 使用虚拟 DOM 的优势如下:
- 简单方便:如果使用手动操作真实 DOM 来完成页面,繁琐又容易出错,在大规模应用下维护起来也很困难
- 性能方面:使用 Virtual DOM,能够有效避免真实 DOM 数频繁更新,减少多次引起重绘与回流,提高性能
- 跨平台:React 借助虚拟 DOM,带来了跨平台的能力,一套代码多端运行
缺点:
- 在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化 首次渲染大量 DOM 时,由于多了一层虚拟 DOM
的计算,速度比正常稍慢
2.你在React项目中是如何使用Redux的? 项目结构是如何划分的?
1.背景
在前面文章了解中,我们了解到redux是用于数据状态管理,而react是一个视图层面的库
如果将两者连接在一起,可以使用官方推荐react-redux库,其具有高效且灵活的特性
react-redux将组件分成:
- 容器组件:存在逻辑处理
- UI 组件:只负责现显示和交互,内部不处理逻辑,状态由外部控制
通过redux将整个应用状态存储到store中,组件可以派发dispatch行为action给store
其他组件通过订阅store中的状态state来更新自身的视图
2.如何做
使用react-redux分成了两大核心:
- Provider
- connection
Provider
在redux中存在一个store用于存储state,如果将这个store存放在顶层元素中,其他组件都被包裹在顶层元素之上
那么所有的组件都能够受到redux的控制,都能够获取到redux中的数据
使用方式如下:
<Provider store = {store}>
<App />
<Provider>
connection
connect方法将store上的getState和 dispatch包装成组件的props
导入conect如下:
import { connect } from "react-redux";
用法如下:
connect(mapStateToProps, mapDispatchToProps)(MyComponent)
可以传递两个参数:
- mapStateToProps
- mapDispatchToProps
mapStateToProps
把redux中的数据映射到react中的props中去
const mapStateToProps = (state) => {
return {
// prop : state.xxx | 意思是将state中的某个数据映射到props中
foo: state.bar
}
}
组件内部就能够通过props获取到store中的数据
class Foo extends Component {
constructor(props){
super(props);
}
render(){
return(
// 这样子渲染的其实就是state.bar的数据了
<div>this.props.foo</div>
)
}
}
Foo = connect()(Foo)
export default Foo
mapDispatchToProps
将redux中的dispatch映射到组件内部的props中
const mapDispatchToProps = (dispatch) => { // 默认传递参数就是dispatch
return {
onClick: () => {
dispatch({
type: 'increatment'
});
}
};
}