端面试题总结
Vue.js是一种构建用户界面的现代JavaScript框架。它旨在轻松开发可维护和可重用的应用程序。Vue框架具有简洁的API,并且易于集成到现有项目中。
前端面试题总结
- vue
- vue
- **1、vue2与vue3的区别**
- **2、vue2响应式原理与vue3响应式原理的区别**
- **3、 watch 、 computed、的区别**
- **4、 setup的作用**
- **5- 选项式API与组合式api的区别**
- **6- ref与reactive的区别**
- **7- 组件通信的六种方式**
- 8- vue3响应式数据的判断?
- 9、vue中hash模式和history模式的区别
- 10、vue2的mixins和vue3的hook有什么区别
- **11- 什么时跨域?如何解决跨域**
- **12、在vue开发时 改变数组或者对象的数据,什么情况页面视图没有更新?如何解决**
- **13、V-if和v-show的区别**
- **14、pinia和vuex的区别**
- **15. 在vue组件中,data为什么是一个返回对象的函数?**
- **16、key的作用**
- **17、keep-alived的作用是什么,使用它的目的是什么?分别有哪些参数**
- **18、vue3. 中pinia有哪些核心属性以及在组件中的使用**
- **19、query 和 params的区别**
- **20、route与router的区别**
- *21、Vue3带来了什么改变?**
- **22、provide 与 inject的使用(vue3)**
- **23、什么是MVVM?工作原理**
- **24、什么虚拟DOM?**
- 25、hook
- 26、Teleport
- 27、toRef与toRefs的区别
- 28、readonly 与 shallowReadonly
- 29、Vue.$nextTick
- 30、v-if 和 v-for 为什么不建议放在一起使用?
- 31、动态路由?
- 32、了解哪些 Vue 的性能优化方法?
- 33、你能解释一下什么是vue.js吗?
- 34、你认为Vue.js有什么优势?
- 35、computed:计算属性
- 36、 watch:监听属性
- 37、如何获取dom
- 38、数据代理
- 39、请简述你对 vue 的理解
- 40、Vue 单页面的优缺点
- 41、写出你对vue的mixin的理解,有什么应用场景?
- 42、什么是路由?
- 43、vuex是什么?
- 44、vue-router路由传参有哪些方法,如何获取路由参数
- 45、写出vue路由中的导航守卫以及导航守卫回调函数中三个参数的作用
- 46、vue-router的作用是什么? 为什么不使用a标签?
- 47、Vuex和单纯的全局对象有什么区别?
- 48、mapState 辅助函数
- 49、各模块在流程中的功能:
- 50、Vuex中 action 和 mutation 的区别
- 51、vue3的常用 Composition API有哪些?
- 52、Vue 3.x中生命周期函数相比Vue 2.x 有变化
- 53、说一下对vue3的理解以及新特性有哪些
- 54、Vue2和vue3的响应式原理分别是什么,以及vue3为什么要更改实现响应式原理的方式
- 55、Vue的过滤器是什么?如何使用?定义一个倒序的过滤器
- 56、Vue是如何实现双向绑定的原理?
- 57、vue3和vue2生命周期的变化,以及compositionApi中的生命周期钩子函数
- 58、单页面应用和多页面应用的区别及优缺点
- 59、keep-alive的作用是什么?什么场景使用?常用属性?生命周期?
- 60、写出vue中的所有的生命周期函数,分别有什么作用
- 61、写出Vue3中watch与watchEffect的区别
- 62、Vue3 中的 Fragments 是什么?以及使用Fragments 的好处
- 63、ref的理解:
- 64、reactive的理解:
- 65、Suspense
- ES6
- javaScript
- css
- React
- 1、React的设计思想
- 2、JSX是什么,它和JS有什么区别
- 3、简述React的生命周期
- 4、React事件处理为什么要手动绑定this
- 5、类组件和函数组件之间的区别是什么?
- 6、react的优缺点
- 7、VUE与React两个框架的区别对比
- 8、React的工作原理以及阻止React的默认行为
- 9、React中diff算法
- 10、props和state
- 11、React可以用两种方法声明组件,他们的区别是什么,什么情况你会选择哪一种?
- 12、React组件生命周期的阶段是什么?
- 13、调用setState之后发生了什么
- 14、什么是 Props?
- 15、React中的状态是什么?它是如何使用的?
- 16、React中的合成事件是什么?
- 17、受控组件和非受控组件
- 18、componentWillUpdate可以直接修改state的值吗
- 19、模仿vue中v-model指令,react实现类似双向绑定
- 20、react无状态组件和class类组件的区别
- 21、React中什么是纯函数
- 22、setState是同步的还是异步的?
- 23、类组件和函数组件之间的区别是什么?
- 24、react中refs是什么?
- 25、state和props区别是什么?
- 26、什么是jsx?
- 27、什么是React 路由
- 28、React有什么特点
- 29、列出React的一些主要优点
- 30、当调用setState时,React render 是如何工作的
- 31、如何避免组件的重新渲染?
- 32、React中的状态是什么?它是如何使用的?
- 33、React 中 key 的重要性是什么?
- 34、模块与组件、模块化与组件化的理解
- 35、如何在 Redux 中定义 Action
- 36、Redux 有哪些优点?
- 37、react中ref的使用方式?
- 38、怎样解释 React 中 render() 的目的
- 39、Store 在 Redux 中的意义是什么
- 40、为什么浏览器无法读取JSX?
- 41、Redux遵循的三个原则是什么?
- 42、解释 Reducer 的作用
vue
(描述后期补充)
vue
1、vue2与vue3的区别
1- vue2与vue3双向绑定数据的原理不同
vue2双向数据绑定采用了es5中Object.defineProperty() 对数据进行了劫持,结合发布订阅模式实现
vue3 采用了es6中的proxy代理对象的方式进行数据交互,相较vue2来说大大的提高了效率
2- vue3支持碎片(Fragments)
支持多个根节点
3- Composition API
Vue2 与vue3 最大的区别是vue2使用选项式api,对比vue3组合式api。旧得选项型api在代码里分割了不同得属性:data,computed,methods等;新得组合式api能让我们使用方法来分割,相比于旧的API使用属性来分组,这样代码会更加简便和整洁
4-建立数据data
vue2是把数据放入data中,vue3就需要使用一个新的setup()方法
备注:此方法在组件初始化构造得时候触发。使用一下三个步骤来建立反应性数据:
1. 从vue引入reactive;
2. 使用reactive() 方法来声明数据为响应性数据;
3. 使用setup()方法来返回我们得响应性数据,从而template可以获取这些响应性数据。
5- 生命周期
vue2 --------------- vue3
beforeCreate -> setup()
Created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroyed -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
--------------------------------------------------------------------
beforeCreate 和 created 已经合并成一个新的函数 setup。
deactivated 和 activated 已经被废弃,取而代之的是 beforeMount 和 beforeUpdate。因为在Vue3中,keep-alive组件被完全重写了,其默认行为现在与没有keep-alive一样。
6- 父子传参不同
父传子,用props,子传父用事件 Emitting Events。
在vue2中,会调用this$emit然后传入事件名和对象;
在vue3中得setup()中得第二个参数content对象中就有emit,那么我们只要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了。
7- 新增setup()函数特性
2、vue2响应式原理与vue3响应式原理的区别
响应式原理就是指的是MVVM的设计模式的核心,即数据驱动页面,一旦数据改变,视图也会跟着改动。
vue2的响应式原理是由Object.defineProperty()实现的 (数据劫持)
vue3的响应式原理是由es6中的Proxy所实现的 (数据代理)
3、 watch 、 computed、的区别
1、computed擅长处理的场景:一个数据受多个数据影响;watch擅长处理的场景:一个数据影响多个数据。
2、功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
3、是否调用缓存:computed支持缓存,只有依赖数据发生改变,才会重新进行计算;而watch不支持缓存,数据变,直接会触发相应的操作。
4、是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。
5、computed不支持异步 ,当computed内有异步操作时无效,无法监听数据的变化;而watch支持异步。
6、computed默认第一次加载的时候就开始监听;watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true(immediate:true)
4、 setup的作用
setup是什么,作用
1、新的选项,所有的组合api函数都在此使用,只在初始化时执行一次
2、函数如果返回对象,对象中的属性与方法,在模板中可以直接使用
执行时机:
1、在beforeCreate之前执行一次,此时组件对象还没有创建
2、This的值为undefined,不能通过this操作 data、computed、methods、props
3、所有的composition api 都不能使用this
返回值:
1、一般都返回一个对象,用于向模板返回数据,返回的数据模板可以直接使用
2、返回的对象的属性与data返回的数据 在组件对象中属性合并
3、返回的对象的方法与methods返回的数据 在组件对象中方法合并
4、切记:
(1)如遇相同名字 setup优先
(2)Methods可以访问setup中属性与方法,setup不可以访问data与methods ,此方式不推荐使用
(3)Setup不能是一个异步函数,如果设置为异步函数返回的是一个promise,模板不能获取到return返回的对象
参数:
setup(props, context) / setup(props, {attrs, slots, emit})
props:接收组件的属性,
context:上下文对象,包括 slots,attrs,emit,expose
(1)attrs: 包含没有在props配置中声明的属性的对象, 相当于 this. a t t r s ( 2 ) s l o t s : 包含所有传入的插槽内容的对象 , 相当于 t h i s . attrs (2)slots: 包含所有传入的插槽内容的对象, 相当于 this. attrs(2)slots:包含所有传入的插槽内容的对象,相当于this.slots
(3)emit: 用来分发自定义事件的函数, 相当于 this.$emit
5- 选项式API与组合式api的区别
在逻辑组织和逻辑复用方面,Composition API是优于Options API
因为Composition API几乎是函数,会有更好的类型推断。
Composition API对 tree-shaking 友好,代码也更容易压缩
Composition API中见不到this的使用,减少了this指向不明的情况
如果是小型组件,可以继续使用Options API,也是十分友好的
6- ref与reactive的区别
定义数据角度:
ref用来定义:基本类型数据。
reactive用来定义:对象(或数组)类型数据。
备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象。
原理角度:
ref通过Object.defineProperty()的get与set来实现响应式(数据劫持)。
reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。
使用角度:
ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value。
reactive定义的数据:操作数据与读取数据:均不需要.value。
7- 组件通信的六种方式
- 父传子 通过在父组件自定义属性,在子组件通过props接收
- 子改父或者子传父 在父组件中通过自定义事件传递方法,在子组件中通过 e m i t 接收自定义事件 < c h i l d r e n @ e v e n t C h a n g e = ” c h a n g e ” > < / c h i l d r e n > t h i s . emit接收自定义事件 <children @ eventChange=”change”></children> this. emit接收自定义事件<children@eventChange=”change”></children>this.emit(‘eventChange’,100)
- 兄弟之间通信 通过一个事件总线(eventBus 其实是一个空实例),在A组件中通过 o n 绑定自定义事件在 B 组件中通过 on绑定自定义事件 在B组件中通过 on绑定自定义事件在B组件中通过emit接收组件
4.通过 p a r e n t / parent / parent/children/$refs $parent指的是父组件实例 c h i l d r e n / children/ children/refs是子组件实例- $attrs & $listeners
a t t r s 获取父组件中不被 p r o p s 接收的自定义属性并且可以通过 v − b i n d = " attrs获取父组件中不被props接收的自定义属性 并且可以通过 v-bind=" attrs获取父组件中不被props接收的自定义属性并且可以通过v−bind="attrs" 传入内部组件
$listeners获取父组件中的自定义事件
6 跨代传参 依赖provide传输数据 通过 inject将数据注入到对应的组件中
7 vuex 、 pinia 可以在任意组件中实现数据共享
8 pubsub-js
PubSub.subscribe()订阅消息
PubSub.publish() 发布消息
8- vue3响应式数据的判断?
isRef: 检查一个值是否为一个 ref 对象
isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
9、vue中hash模式和history模式的区别
Vue底层对它们的实现方式不同:
hash模式是依靠onhashchange事件(监听location.hash的改变)
history模式是主要是依靠的HTML5 history中新增的两个方法,pushState()可以改变url地址且不会发送请求,replaceState()可以读取历史记录栈,还可以对浏览器记录进行修改。
当真正需要通过URL向后端发送HTTP请求的时候,比如常见的用户手动输入URL后回车,或者是刷新(重启)浏览器,这时候history模式需要后端的支持。因为history模式下,前端的URL必须和实际向后端发送请求的URL一致,例如有一个URL是带有路径path的(例如www.libai.wang/blogs/id),如果后端没有对这个路径做处理的话,就会返回404错误。所以需要后端增加一个覆盖所有情况的候选资源,一般会配合前端给出的一个404页面。
10、vue2的mixins和vue3的hook有什么区别
mixins是什么?
开发中常常会遇到一些具有相同逻辑和功能的组件,
mixins就是将这些多个相同的逻辑抽离出来,各个组件只需要引入mixins,就能实现一次写代码,多组件收益的效果
特性1
mixins中的生命周期会与引入mixins的组件的生命周期整合在一起调用,但是mixins的生命周期比组件快
特性2
组件的data/methods/filters会覆盖mixins里的同名data/methods/filters
缺点
1、变量和方法来源不明确,隐式传入
2、多个mixins融合到一起会有冲突
hook函数是什么?
特性1
hook是使用vue3的组合API封装的可复用的功能函数
特性2
类似于vue2的mixin技术
优点
变量和方法都是显示传入,解决了来源不明的问题
11- 什么时跨域?如何解决跨域
跨域是如何形成的?
当我们请求一个url的 协议、域名、端口三者之间任意一个与当前页面url的协议、域名、端口 不同这种现象我们把它称之为跨域
(了解)跨域会导致:
1、无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
2、无法接触非同源网页的 DOM
3、无法向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)
解决方案:
1.jsonp 只能解决get跨域
2.服务器代理 通过配置vue.Config.js文件实现
12、在vue开发时 改变数组或者对象的数据,什么情况页面视图没有更新?如何解决
方式1:使用this.$set() 或者 Vue.set()
– 给对象赋值
//Object:目标对象 key 属性名称 value 值
this.$set(Object,key,value)
– 给数组赋值
//Array:目标数组 index元素索引 value 值
this.$set(Array,index,value)
方式2:使用Object.assign()
13、V-if和v-show的区别
1- 操作 v-if:向DOM树添加或者删除DOM元素 v-show:控制css中display属性 进行元素的显示与隐藏 2- 编译过程 v-if:局部编译卸载的过程:在切换过程中,销毁或者重建 组件中的事件与子组件 v-show:执行css的切换 3- 编译条件 v-if:惰性,只有条件为true的时候才会编译解析组件 v-show:任何情况下都会自动加载,然后控制元素的显示与隐藏 4- 性能消耗 v-if:切换消耗高 v-show:只有初始渲染消耗 5- 使用场景 v-if:改变频率不频繁 v-show:频繁切换
14、pinia和vuex的区别
1.pinia没有mutations,只有state,getters,actions
2.pinia分模块不需要modules (之前vuex分模块需要modules)
3.pinia体积更小(性能更好)
4.pinia可以直接修改state数据
15. 在vue组件中,data为什么是一个返回对象的函数?
如果data是对象的话,由于对象是引用类型,组件被复用的话,就会创建多个实例。本质上,这些实例用的都是同一个构造函数。这样就会影响到所有的实例,所以为了保证组件不同的实例之间data不冲突,data必须是一个函数。
16、key的作用
1、主要是为了高效的更新虛拟DOM,其原理是vue在patch(补丁)过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。
2、 另外,若不设置key还可能在列表更新时引发一些隐蔽的bug。如某行数据不该更新的却更新了。
3、vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果
-或者--------------------------------------------------------------------------------------
1- 唯一标识
2.因为虚拟 dom 有一个 diff 算法,key 是唯一的,不会让数据产生混乱,可以高效更新的虚拟
dom
不建议使用索引作为 key,可以使用唯一 id 作为 key
原因:如果在一个数组中插入某一个值,vue 识别后会从新分配后续索引,速度变慢, 当
删除一条数据时,他的索引也会发生变化,会让数据产生混乱
17、keep-alived的作用是什么,使用它的目的是什么?分别有哪些参数
Keep-alive 是 Vue.js 内置的一个抽象组件,用于缓存有状态组件,可以在组件切换时保留组件的状态避免重新渲染。它有以下两个作用:
1- 缓存有状态的组件,避免组件在切换时被重新渲染;
2- 在缓存的组件被激活时触发 activated 钩子函数,在缓存的组件被停用时触发 deactivated 钩子函数。
目的:使用 Keep-alive 可以提高组件的性能,尤其是在组件状态比较复杂或需要较长时间计算的情况下,通过缓存组件避免重复渲染,提高应用的性能。
属性:
① include:字符串或正则,只有名称匹配的组件会被缓存。
② exclude:字符串或正则,任何名称匹配的组件都不会被缓存。
③ max:数字,最多可以缓存多少组件实例。
18、vue3. 中pinia有哪些核心属性以及在组件中的使用
pinia是Vue3中的状态管理库,具有以下核心属性:
$state:一个ref对象,用于存储状态数据。
$getters:一个包含所有状态的getter函数的对象。
$actions:一个包含所有操作状态的action函数的对象。
在组件中使用pinia,需要通过useStore方法来获取一个与组件相关联的状态管理对象。
19、query 和 params的区别
query
1.是拼接在url后面的参数。
2.参数在?后面,且参数之间用&符分隔
3.query相当于get请求,可以在地址栏看到参数
params
1.是路由的一部分。以对象的形式传递参数
2.使用params传参只能由name引入路由,如果写成path页面会显示警告,说参数会被忽略
3.params相当于post请求,参数不会再地址栏中显示
或者
1、query 传参配置的是 path,而 params 传参配置的是 name,在 params 中配置 path 无效
2、query 在路由配置不需要设置参数,而 params 必须设置
3、query 传递的参数会显示在地址栏中
4、params 传参刷新会无效,但是 query 会保存传递过来的值,刷新不变 ;
5、接收参数使用 this.$router 后面就是搭配路由的名称就能获取到参数的值
20、route与router的区别
$route:获取路由信息 指当前路由实例跳转到的路由对象
包括:
$route.path 字符串,等于当前路由对象的路径,会被解析为绝对路径,如/home/ews
$route.name 当前路由的名字,如果没有使用具体路径,则名字为空
$route.router 路由规则所属的路由器
$route.matched 数组,包含当前匹配的路径中所包含的所有片段所对象的配置参数对
象
$route.query 对象,包含路由中查询参数的键值对。会拼接到路由 url 后面
$route.params 对象,含路有种的动态片段和全匹配片段的键值对,不会拼接到路由
的 url 后面
r o u t e r :获取路由整个实例指整个路由实例,可操控整个路由通过‘ router:获取路由整个实例 指整个路由实例,可操控整个路由 通过‘ router:获取路由整个实例指整个路由实例,可操控整个路由通过‘router.push’往其中添加任意的路由对象 钩子函数等
21、Vue3带来了什么改变?*
1.性能的提升
打包大小减少41%
初次渲染快55%, 更新渲染快133%
内存减少54%
2.源码的升级
使用Proxy代替defineProperty实现响应式
重写虚拟DOM的实现
3.Vue3可以更好的支持TypeScript
新的特性-Composition API(组合API)
22、provide 与 inject的使用(vue3)
作用:实现祖与后代组件间通信
套路:父组件有一个 provide 选项来提供数据,后代组件有一个 inject 选项来开始使用这些数据
具体写法:
祖组件中:
setup(){
......
let car = reactive({name:'奔驰',price:'40万'})
provide('car',car)
......
}
-----------------------------------------------------
后代组件中:
setup(props,context){
......
const car = inject('car')
return {car}
......
}
23、什么是MVVM?工作原理
MVVM是Model-View-ViewModel的缩写。MVVM是一种设计思想。
View层是视图层,也就是用户界面。前端主要由HTML和CSS来构建;
Model层 是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,对于前端来说就是后端的提供的API接口;
ViewModel层是视图数据层,一个同步View和Model的对象。
在MVVM架构下,View和Model之间并没有直接的联系,而是通过ViewModel进行交互,Model和ViewModel之间的交互是双向的,因此View数据的变化会同步到Model中,而Model数据的变化也会立即反应到View上。
ViewModel通过双向数据绑定把View层和Model层连接了起来,而View和Model之间的同步工作完全是自动的,无需人为干涉,因此开发者只需要关注业务逻辑,不需要手动操作DOM,不需要关注数据状态的同步问题,复杂的数据状态维护完全由MVVM来统一管理。
24、什么虚拟DOM?
概念:
虚拟DOM其实就是用一个原生的JS对象去描述一个DOM节点,实际上它只是对真实 DOM 的一层抽象。最终可以通过一系列操作使这棵树映射到真实环境上。
相当于在js与DOM之间做了一个缓存,利用patch(diff算法)对比新旧虚拟DOM记录到一个对象中按需更新, 最后创建真实的DOM
虚拟dom原理流程:
模板 ==> 渲染函数 ==> 虚拟DOM树 ==> 真实DOM
vuejs通过编译将模板(template)转成渲染函数(render),执行渲染函数可以得到一个虚拟节点树
在对 Model 进行操作的时候,会触发对应 Dep 中的 Watcher 对象。Watcher 对象会调用对应的 update 来修改视图。
虚拟 DOM 的实现原理主要包括以下 3 部分:
用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
diff 算法 — 比较两棵虚拟 DOM 树的差异;
pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
25、hook
-- hook本质是一个函数,把setup函数中使用的Composition API进行了封装。类似于vue2.x中的mixin。
-- 自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。
26、Teleport
Teleport 是一种能够将我们的组件html结构移动到指定位置的技术。
<teleport to="移动位置">
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>我是一个弹窗</h3>
<button @click="isShow = false">关闭弹窗</button>
</div>
</div>
</teleport>
27、toRef与toRefs的区别
作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。
语法:const name = toRef(person,‘name’)
应用: 要将响应式对象中的某个属性单独提供给外部使用时。
扩展:toRefs 与toRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)
28、readonly 与 shallowReadonly
readonly: 让一个响应式数据变为只读的(深只读)。
shallowReadonly:让一个响应式数据变为只读的(浅只读)。
应用场景: 不希望数据被修改时。
29、Vue.$nextTick
**在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。 **
使用场景:
1- 如果想要在修改数据后立刻得到更新后的DOM结构,可以使用Vue.nextTick()
2- 在created生命周期中进行DOM操作
【以下内容了解】
1 - nextTick 是 Vue 提供的一个全局 API,由于 Vue 的异步更新策略,导致我们对数据修改后不会直接体现在 DOM 上,此时如果想要立即获取更新后的 DOM 状态,就需要借助该方法。
2- Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue 将开启一个异步更新队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入队列一次。
3- 这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。nextTick方法会在队列中加入一个回调函数,确保该函数在前面的 DOM 操作完成后才调用。
30、v-if 和 v-for 为什么不建议放在一起使用?
Vue 2 中,v-for的优先级比v-if高,这意味着v-if将分别重复运行于每一个v-for循环中。如果要遍历的数组很大,而真正要展示的数据很少时,将造成很大的性能浪费。
Vue 3 中,则完全相反,v-if的优先级高于v-for,所以v-if执行时,它调用的变量还不存在,会导致异常。
31、动态路由?
很多时候,我们需要将给定匹配模式的路由映射到同一个组件,这种情况就需要定义动态路由。
例如,我们有一个 User组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用动态路径参数(dynamic segment)来达到这个效果:{path: ‘/user/:id’, compenent: User},其中:id就是动态路径参数。
32、了解哪些 Vue 的性能优化方法?
1- 路由懒加载。有效拆分应用大小,访问时才异步加载。
2- keep-alive缓存页面。避免重复创建组件实例,且能保留缓存组件状态。
3- v-for遍历避免同时使用v-if。实际上在 Vue 3 中已经是一个错误用法了。
4- 长列表性能优化,可采用虚拟列表。
5- v-once。不再变化的数据使用v-once。
6- 事件销毁。组件销毁后把全局变量和定时器销毁。
7- 图片懒加载。
8- 第三方插件按需引入。
9- 子组件分割。较重的状态组件适合拆分。
10- 服务端渲染。
33、你能解释一下什么是vue.js吗?
Vue.js是一种构建用户界面的现代JavaScript框架。它旨在轻松开发可维护和可重用的应用程序。Vue框架具有简洁的API,并且易于集成到现有项目中。
34、你认为Vue.js有什么优势?
Vue.js的优点包括:
1- 非常轻量级, 在网页上加载速度很快
2- 可以使用模板或者单文件组件结构构建Realtime数据绑定
3- 组件化和模块化开发
4- 流畅的API,包括生命周期钩子
5- 易于学习和使用
35、computed:计算属性
1- 自身需要依赖另一个值得改变而使当前所在DOM更新
2- 计算属性不可以与data中的数据重名
3- 计算属性的方法不需要加括号调用,方法需要单独加括号调用 因为 计算属性 不属于方法 属于属性
4- 计算属性具有缓存机制
当计算属性第一次获取到响应式数据时,会缓存,在后期渲染视图时,会观察响应式数据是否改变,如果改变会调用计算属性,如果没有改变会读取存储的数据,方法只用更新就会重新调用
5- 当获取计算属性时会触发getter ,当设置修改计算机属性是会触发setter
注意:计算属性不可以使用箭头函数,否则this不会指向这个组件的实例
36、 watch:监听属性
1- 当检测的值发生改变时,那么对应的方法会自动执行
2- deep 开启深度监视
发现对象内部值得变化,可以在选项参数中指定deep:true 作为深度监视,但是监听数组的变更则不需要使用
3- immediate
在选项参数中指定immediate:true将立即以表达式的当前值触发回调
37、如何获取dom
1、在我们的vue项⽬中,难免会因为引⽤第三⽅库⽽需要操作DOM标签,vue为我们提供了ref属性。 ref 被⽤来给元素或⼦组件注册引⽤信息。
引⽤信息将会注册在⽗组件的 $refs 对象上。如果在普通的 DOM 元素上使⽤,引⽤指向的就是 DOM 元素;如果⽤在⼦组件上,引⽤就指向组件实例
2.通过event事件对象
3.通过自定义指令:directive(el)的参数el
38、数据代理
通过一个对象代理另一个对象中属性的操作(读get、写set)
vue中的数据代理:
通过 vm 来代理 data对象中属性的操作
为什么使用数据代理:
更加方便的操作data中的数据
数据代理的工作原理:
Object.defineproperty()把data对象中所有属性添加到vm上,为每添加的每一个属性都制定了getter和setter,
可以通过getter和setter对data对象中属性执行读与写的操作
39、请简述你对 vue 的理解
Vue 是一套构建用户界面的渐进式的自底向上增量开发的 MVVM 框架,
核心是关注视图层,vue 的核心是为了解决数据的绑定问题,为了开发大
型单页面应用和组件化,所以 vue 的核心思想是数据驱动和组件化,这
里也说一下 MVVM 思想,MVVM 思想是 模型 视图 vm 是 v 和 m 连
接的桥梁,当模型层数据修改时,VM 层会检测到,并通知视图层进行相
应修改
40、Vue 单页面的优缺点
单页面 spa
优点:前后端分离 用户体验好 一个字 快 内容改变不需要重新加载整
个页面
缺点:不利于 seo, 初次加载时耗长(浏览器一开始就要加载 html css
js ,所有的页面内容都包含在主页面中) ,页面复杂度提高了,导航不
可用
41、写出你对vue的mixin的理解,有什么应用场景?
mixin(混入),提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。
本质其实就是一个js对象,它可以包含我们组件中任意功能选项,如data、components、methods、created、computed等等
我们只要将共用的功能以对象的方式传入 mixins选项中,当组件使用 mixins对象时所有mixins对象的选项都将被混入该组件本身的选项中来
在Vue中我们可以局部混入跟全局混入
使用场景
在日常的开发中,我们经常会遇到在不同的组件中经常会需要用到一些相同或者相似的代码,这些代码的功能相对独立
这时,可以通过Vue的mixin功能将相同或者相似的代码提出来
42、什么是路由?
Vue Router 是 Vue.js 官方的路由管理器,或者说是SPA(单页应用)的路径管理器。再通俗的
说,vue-router就是WebApp的链接路径管理系统。
它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。
vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。
传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则
是路径之间的切换,也就是组件的切换。路由模块的本质 就是建立起url和页面之间的映射关
系。
43、vuex是什么?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,
Vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间的数据共享
并以相应的规则保证状态以一种可预测的方式发生变化(响应式的)。Vuex 也集成到 Vue 的官方调试工具 devtools extension (opens new window)
44、vue-router路由传参有哪些方法,如何获取路由参数
params⽅法传参的时候,要在路由后⾯加参数名占位;并且传参的时候,参数名要跟路由后⾯设置的参数名对应。
/user/:id这个路由匹配/user/111, /user/222这⾥的 id就是 params
query⽅法,就没有这种限制,直接在跳转⾥⾯⽤就可以。
query传参和params传参的区别
1)query 传参配置的是 path,而 params 传参配置的是name,且在 params中配置 path 无效
2)query传递的参数会显示在地址栏中,而params传参不会
3)query传参刷新页面数据不会消失,而params传参刷新页面数据回消失
4)params可以使用动态传参,动态传参的数据会显示在地址栏中,且刷新页面不会消失,因此可以使用动态params传参,根据动态传递参数在传递页面获取数据,以防页面刷新数据消失
45、写出vue路由中的导航守卫以及导航守卫回调函数中三个参数的作用
全局守卫:beforeEach,afterEach
局部守卫:
beforeRouteEnter:因为当守卫执行前,组件实例还没被创建,不能获取组件实例的this
beforeRouteUpdate: 在当前路由改变,但是该组件被复用时调用,可以访问组件实例 this
beforeRouteLeave:导航离开该组件的对应路由时调用,可以访问组件实例 this
每个守卫方法接收三个参数:
to:目标路由对象
from:准备要离开的路由
next():进行管道中的下一个钩子。可传递参数有布尔值false,直接写路径’/‘或{path:’/'},回调函数
注意:后置钩子函数afterEach不会接受next函数也不会改变导航本身。
46、vue-router的作用是什么? 为什么不使用a标签?
用于页面跳转
a标签的作用是从当前页面跳转到另外一个页面,相当于重新加载了页面,还要重新渲染页面,增加了对DOM性能的损耗,vue-router不会重新渲染,它会选择路由所指的组件进行渲染
47、Vuex和单纯的全局对象有什么区别?
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
48、mapState 辅助函数
当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。
为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,让你少按几次键
49、各模块在流程中的功能:
Vue Components:Vue组件。HTML页面上,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。
dispatch:操作行为触发方法,是唯一能执行action的方法。
actions:操作行为处理模块,由组件中的$store.dispatch(‘action 名称’, data1)来触发。然后由commit()来触发mutation的调用 , 间接更新 state。可以定义异步函数,并在回调中提交mutation,就相当于异步更新了state中的字段
commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
mutations:状态改变操作方法,由actions中的commit(‘mutation 名称’)来触发。是Vuex修改state的唯一推荐方法。该方法只能进行同步操作,且方法名只能全局唯一。
state:state中存放页面共享的状态字段
getters:相当于当前模块state的计算属性
50、Vuex中 action 和 mutation 的区别
Action 可以包含任意异步操作。
Action 提交的是 mutation,而不是直接变更状态。
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,
因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
51、vue3的常用 Composition API有哪些?
1.setup 2.ref函数 3.reactive函数 4.Vue3.0中的响应式原理
5.计算属性 6.监听属性 7.Vue3.0生命周期 8.Teleport
52、Vue 3.x中生命周期函数相比Vue 2.x 有变化
Vue 3.x中的生命周期函数相比Vue 2.x发生了一些变化:
beforeCreate 和 created 已经合并成一个新的函数 setup。
deactivated 和 activated 已经被废弃,取而代之的是 beforeMount 和 beforeUpdate。因为在Vue3中,keep-alive组件被完全重写了,其默认行为现在与没有keep-alive一样。
53、说一下对vue3的理解以及新特性有哪些
Vue3 是 Vue.js 的最新版本,相比于 Vue2,它带来了许多变化和升级
新特性:
1)更快的渲染速度:Vue3 通过重写了 reactivity system 和 compiler,显著提高了渲染性能。
2)Composition API:Vue3 引入了 Composition API,允许开发者将一个组件的逻辑分割成可复用的逻辑代码块,提高了组件的可复用性,并且使代码更加清晰简洁。
3)Teleport:Teleport 是 Vue3 中新引入的功能,允许你将一个组件渲染到 DOM 树中的任何位置,使得像模态框这类弹出式组件的实现变得更加容易。
4)更好的 Typescript 支持:Vue3 深度整合了 Typescript,提供更好的类型检查和代码补全功能。
5)其他改进:Vue3 中还有一些其他的改进,如支持 Fragments、更好的警告和错误提示等等。
54、Vue2和vue3的响应式原理分别是什么,以及vue3为什么要更改实现响应式原理的方式
Vue2中使用的响应式原理是通过Object.defineProperty方法对数据进行劫持监听,从而实现数据的响应式更新。
而Vue3中使用的响应式原理是基于ES6的Proxy实现的,通过Proxy对象代理数据,可以实现更高效的数据监听和更新,同时也可以监听到数组的变化。
55、Vue的过滤器是什么?如何使用?定义一个倒序的过滤器
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示:
{{ message | capitalize }}
filters: {
capitalize: function (value) {
if (!value) return ‘’
return value.split(‘’).reverse().join(‘’)
}
}
56、Vue是如何实现双向绑定的原理?
vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue实例来作为它的 data选项时,Vue将遍历它的属性,用Object.defineProperty()将它们转为getter/setter。用户看不到getter/setter,但是在内部它们让Vue追踪依赖,在属性被访问和修改时通知变化。
57、vue3和vue2生命周期的变化,以及compositionApi中的生命周期钩子函数
1、Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名:
beforeDestroy改名为 beforeUnmount
destroyed改名为 unmounted
2、Vue3.0也提供了 Composition API 形式的生命周期钩子,Option API形式的钩子对应关系如下:
beforeCreate===>setup()
created=======>setup()
beforeMount =>onBeforeMount
mounted=====>onMounted
beforeUpdate===>onBeforeUpdate
updated =======>onUpdated
beforeUnmount ==>onBeforeUnmount
unmounted =====>onUnmounted
58、单页面应用和多页面应用的区别及优缺点
单页面应用(spa),通俗一点说就是只有一个主页面的应用,浏览器一开始要加载所有的html,js,css 所有的页面内容都包含在这个所谓的主页面中,但是在写的时候,还是会分开写(页面片段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源,多应用pc端.
多页面(mpa): 就是指一个应用中有多个页面,页面跳转是是整页刷新
单页面的优点: 用户体验好,快,内容的改变不需要加载整个页面,基于这一点spa对服务器压力较小,前后端的能力;页面效果会比较炫酷(比如切换页面内容时的专场动画).
单页面缺点: 不利于seo,导航不可用,如果一定要导航需要自行实现前进,后退(忧郁是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理);初次加载耗时多,页面复杂度提高
59、keep-alive的作用是什么?什么场景使用?常用属性?生命周期?
Keep-alive 是 Vue.js 内置的一个抽象组件,用于缓存有状态组件,可以在组件切换时保留组件的状态避免重新渲染。它有以下两个作用:
缓存有状态的组件,避免组件在切换时被重新渲染;
在缓存的组件被激活时触发 activated 钩子函数,在缓存的组件被停用时触发 deactivated 钩子函数。
使用 Keep-alive 可以提高组件的性能,尤其是在组件状态比较复杂或需要较长时间计算的情况下,通过缓存组件避免重复渲染,提高应用的性能。
60、写出vue中的所有的生命周期函数,分别有什么作用
beforecreate:实例已经初始化,但不能获取DOM节点。(没有data,没有el)
created:实例已经创建,仍然不能获取DOM节点。(有data,没有el)
载入阶段:
beforemount:模板编译完成,但还没挂载到界面上。(有data,有el)
mounted:编译好的模板已挂载到页面中(数据和DOM都已经渲染出来)。
更新阶段:
beforeupdate:数据发生变化立即调用,此时data中数据是最新的,但页面上数据仍然是旧的(检测到数据更新时,但DOM更新前执行)。
updated:更新结束后执行,此时data中的值和页面上的值都是最新的。
销毁阶段:
beforedestroy:当要销毁vue实例时,在销毁之前执行。
destroy:在销毁vue实例时执行。
actived 在keep-alive中使用,缓存组件激活
deactived 在keep-alive中使用,缓存组件不激活
61、写出Vue3中watch与watchEffect的区别
Vue3中的watch和watchEffect都用于监听数据的变化,但是它们之间有以下区别:
watch需要显式地监听数据变化,并且需要指定回调函数。在回调函数中可以处理数据变化的逻辑,也可以手动处理数据,因此灵活性更高。watch可以监听多个数据。
watchEffect则可以自动监听函数内部的响应式数据的变化,只要其内部引用的响应式数据发生变化,回调函数就会被调用。watchEffect不需要显式地声明监听哪些数据,因此代码更简洁,但也意味着它无法监听特定的数据。
62、Vue3 中的 Fragments 是什么?以及使用Fragments 的好处
在Vue3版本中,fragments函数是一个用于简化组件模板编写的新特性。它的作用类似于Vue2版本中的template标签,但是在实际使用中,fragments函数更为方便和高效。
在Vue2版本中,模板是通过template标签进行编写的。但是,在某些情况下,template标签带来的开销是很大的,因为它本身是一个生成虚拟节点的过程,而虚拟节点的生成会消耗一定的性能。这时候,我们可以使用fragments函数来替代template标签,从而更快速地生成组件。
另外,使用fragments函数可以更好地控制组件的结构和样式,使得组件的代码更为简洁明了,易于维护和更新。
63、ref的理解:
1)、功能:接受一个内部值,返回一个响应式的、可更改的 ref 对象,ref对象只有一个属性:value。
2)、使用ref对象:模板上不需要写 .value 属性(会自动解构),在js中,使用 .value 来完成数据的读写。
3)、ref接收基本类型和引用类型
ref可以接收基本类型。当接收的值为引用类型是,会自动将一个ref对象转为proxy对象
关键词:value,响应式,
64、reactive的理解:
1)功能:
接收普通对象数据,返回一个响应式代理对象,这个普通对象可以是多个数据
2)使用:
操作属性时,可以直接使用,不需要通过.value获取
3)注意:
a. 响应式转换是“深层的”会影响对象内部多有嵌套的属性
b. 通过代理对象,源对象的内部数据也是响应式的
关键词:对象、proxy、深层、数组、Map
65、Suspense
等待异步组件时渲染一些额外内容,让应用有更好的用户体验
使用步骤:
异步引入组件
import {defineAsyncComponent} from ‘vue’
const Child = defineAsyncComponent(()=>import(‘./components/Child.vue’))
使用Suspense包裹组件,并配置好default 与 fallback
<template>
<div class="app">
<h3>我是App组件</h3>
<Suspense>
<template v-slot:default>
<Child/>
</template>
<template v-slot:fallback>
<h3>加载中.....</h3>
</template>
</Suspense>
</div>
</template>
ES6
1- 写出对promise的理解
Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
通俗讲,Promise是一个许诺、承诺,是对未来事情的承诺,承诺不一定能完成,但是无论是否能完成都会有一个结果。
Pending 正在做。。。
Resolved 完成这个承诺
Rejected 这个承诺没有完成,失败了
Promise 用来预定一个不一定能完成的任务,要么成功,要么失败
在具体的程序中具体的体现,通常用来封装一个异步任务,提供承诺结果
Promise 是异步编程的一种解决方案,主要用来解决回调地狱的问题,可以有效的减少回调嵌套。真正解决需要配合async/await
2- js实现对象深浅拷贝(至少两种方法)
方法一:使用JSON.stringify和JSON.parse
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
该方法首先使用JSON.stringify将对象转为JSON字符串,然后再使用JSON.parse将JSON字符串转为对象。该方法的缺点是不能拷贝函数和Symbol等特殊类型的属性。
方法二:递归实现
function deepClone(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
let result = Array.isArray(obj) ? [] : {};
for (let key in obj) {
result[key] = deepClone(obj[key]);
}
return result;
}
该方法通过递归的方式实现深拷贝,能够拷贝对象中的所有属性,包括函数和Symbol等特殊类型的属性。但是如果对象嵌套层数过多,可能会导致栈溢出的问题。
3、箭头函数与普通函数的区别
箭头函数是匿名函数,不能作为构造函数,不能使用 new
箭头函数不能绑定 arguments,要用 rest 参数解决
箭头函数没有原型属性
箭头函数的 this 永远指向其上下文的 this,
箭头函数不能绑定 this,会捕获其所在的上下文的 this 值,作为自己的
this
javaScript
1什么是原型与原型链
原型
JS声明构造函数(用来实例化对象的函数)时,会在内存中创建一个对应的对象,这个对象就是原函数的原型。构造函数默认有一个prototype属性,prototype的值指向函数的原型。同时原型中也有一个constructor属性,constructor的值指向函数对象。
通过构造函数实例化出来的对象,并不具有prototype属性,其默认有一个__proto__属性,__proto__的值指向构造函数的原型。在原型对象上添加或修改的属性,在所有实例化出的对象上都可共享。
原型的作用:
1.数据共享 节约内存内存空间
2.实现继承
原型链
当在实例化的对象中访问一个属性时,首先会在该对象内部(自身属性)寻找,如找不到,则会向其__proto__指向的原型中寻找,如仍找不到,则继续向原型中__proto__指向的上级原型中寻找,直至找到或Object.prototype.__proto__为止(值为null),这种链状过程即为原型链。如下图所示好理解(根据代码参考下图)
原型链的作用:
查找对象的属性(方法)
(了解)
Object.prototype.constructor.proto === Function.prototype // true
Function.prototype.proto === Object.prototype // true
Object.prototype.proto === null // true
2、本地存储与cookie区别【Cookie,localStorage,sessionStorage】
三者的异同
1.特性
Cookie 临时存储
localStorage 永久存储
sessionStorage 临时存储
2. 数据的生命期
Cookie:一般由服务器生成,可设置失效时间。如果在浏览器端生成 Cookie,默认是关闭浏览器后失效
localStorage,sessionStorage:除非被清除,否则永久保存仅在当前会话下有效,关闭页面或浏览器后被清除
3.存放数据大小
Cookie:4K 左右
localStorage,sessionStorage:一般为 5MB
4.与服务器端通信
Cookie:每次都会携带在 HTTP 头中,如果使用 cookie 保存过多数据会带来性能问题
localStorage,sessionStorage:仅在客户端(即浏览器)中保存,不参与和服务器的通信
5.易用性
Cookie:需要程序员自己封装,源生的 Cookie 接口不友好
localStorage,sessionStorage:源生接口可以接受,亦可再次封装来对 Object 和 Array 有更好的支持
3-数组去重的方式
1、filter()和indexOf()实现去重
let arr= [1, 2, 3, 4, 1, 2, 3, 4]
let newArr= arr.filter((item, index, array) => {
return arr.indexOf(item) === index
})
// newArr=== [1, 2, 3, 4]
2、reduce()和includes()实现去重
let originalArray = [1, 2, 3, 4, 1, 2, 3, 4]
let uniqueArray = originalArray.reduce((unique, item) => {
unique.includes(item) ? unique : [...unique, item]
}, [])
// uniqueArray === [1, 2, 3, 4]
3、Set实现去重
let originalArray = [1, 2, 3, 4, 1, 2, 3, 4]
let uniqueArray = array => [...new Set(array)]
// or
let uniqueArray = Array.from(new Set(originalArray))
// uniqueArray = [1, 2, 3, 4]
4、js数据类型有哪些?如何判断?数据类型强制转换和隐式转换的区别
JS基本数据类型有:Number, String, Boolean, Null, Undefined,object ,Symbol。
判断方法:
- typeof操作符
- Object.prototype.toString.call()方法
- instanceof操作符
- constructor属性
区别:
- 强制类型转换是人为地将一种数据类型转换为另一种数据类型,比如使用Number()将字符串转换为数字。
- 隐式类型转换是JS引擎自动进行的类型转换,比如在字符串和数字相加时,JS会将数字隐式地转换为字符串。
5、JS 中的作用域和作用域链?
作用域,即变量(变量作用域又称上下文)和函数生效(能被访问)的区域或集合。作用域决定了代码区块中变量和其他资源的可见性。一般可分为:全局作用域、局部作用域(函数作用域)、块级作用域。
全局作用域任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问。
局部作用域也叫做函数作用域,如果一个变量是在函数内部声明的,它就在一个函数作用域下面。这些变量只能在函数内部访问,不能在函数以外去访问。
块级作用域凡是代码块就可以划分变量的作用域,这种作用域的规则就叫做块级作用域。
作用域链当在 JS 中使用一个变量时,JS 引擎会尝试在当前作用域下寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推,直至找到该变量或是查找至全局作用域,如果在全局作用域里仍然找不到该变量,它就会在全局范围内隐式声明该变量(非严格模式下)或是直接报错。
6、闭包?
闭包就是能够读取其他函数内部变量的函数。主要作用是解决变量污染问题,也可以用来延长局部变量的生命周期。
优点:延长局部变量的生命周期
缺点:会导致函数的变量一直保存在内存中,过多的闭包可能会导致内存泄漏
7、new 操作符的实现机制?
- 首先创建了一个新的空对象
- 设置原型,将对象的原型设置为函数的prototype对象。
- 让函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)
- 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象
function myNew(context) {
const obj = new Object();
obj.__proto__ = context.prototype;
const res = context.apply(obj, [...arguments].slice(1));
return typeof res === "object" ? res : obj;
}
8、浅拷贝和深拷贝的实现?
**浅拷贝:**如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存地址。即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址。常用的方法有:object.assgin,扩展运算符等等
**深拷贝:**开辟一个新的栈,两个对象的属性完全相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。
【浅拷贝代码说明】
var a = { count: 1, deep: { count: 2 } }; var b = Object.assign({}, a); // 或者 var c = {...a}; // 实现一个浅拷贝 function shallowClone(obj) { const newObj = {}; for (let prop in obj) { if (obj.hasOwnProperty(prop)) { newObj[prop] = obj[prop]; } } return newObj }
#### 【深拷贝代码说明】
```javascript
/**
* 深拷贝
* @param {Object} obj 要拷贝的对象
* @param {Map} map 用于存储循环引用对象的地址
*/
function deepClone(obj = {}, map = new Map()) {
if (obj === null) return obj // 如果是null或者undefined我就不进行拷贝操作
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
// 可能是对象或者普通的值 如果是函数的话是不需要深拷贝
if (typeof obj !== 'object') return obj
if (map.get(obj)) {
return map.get(obj);
}
let result = {}; // 初始化返回结果
if (
obj instanceof Array ||
// 加 || 的原因是为了防止 Array 的 prototype 被重写,Array.isArray 也是如此
Object.prototype.toString(obj) === "[object Array]"
) {
result = [];
}
// 防止循环引用
map.set(obj, result);
for (const key in obj) {
// 保证 key 不是原型属性
if (obj.hasOwnProperty(key)) {
// 递归调用
result[key] = deepClone(obj[key], map);
}
}
return result;
}
css
1、外边距重叠 解决方案
1.外层元素padding代替
2.内层元素透明边框 border:1px solid transparent;
3.内层元素绝对定位 postion:absolute:
4.外层元素 overflow:hidden;
5.内层元素 加float:left;或display:inline-block;
6.内层元素padding:1px;
flex 布局的原理 以及属性介绍
flex布局原理:
就是通过给父盒子添加flex属性,来控制子盒子的位置和排列方式。
flex 属性定义子项目分配剩余空间,用flex来表示占多少份数。
.align-self 控制子项自己在侧轴上的排列方式
order 属性定义项目的排列顺序
2、列举几种移动端适配方案
所谓移动端适配,就是WebApp在不同尺寸的屏幕上等比显示
第一种方法:viewport适配
原理:通过设置 initial-scale , 将所有设备布局视口的宽度调整为设计图的宽度.
第二种方法:借助media实现rem适配
rem:CSS的长度单位, 根元素字体大小的倍数,只有根元素字体大小有关; html 中的根元素即 html 元素。
大部分浏览器的默认字体大小都是16px,所以1rem = 16px;
rem适配原理:
长度单位都是用 rem 设置
当屏幕尺寸改变时,只需要修改 html 元素的 font-size 即可实现等比适配
我们在制作页面的时候,只考虑跟设计稿相同的屏幕尺寸即可,其他尺寸屏幕自动适配
第三种方法:JS配合修改配合rem适配
第四种方法:JS动态修改配合CSS预处理器(less)
第五种方法:JS动态修改配合rem适配
React
1、React的设计思想
组件化
每个组件都符合开放-封闭原则,封闭是针对渲染工作流来说的,指的是组件内部的状态都由自身维护,只处理内部的渲染逻辑。开放是针对组件通信来说的,指的是不同组件可以通过props(单项数据流)进行数据交互
数据驱动视图
UI=f(data)
通过上面这个公式得出,如果要渲染界面,不应该直接操作DOM,而是通过修改数据(state或prop),数据驱动视图更新
虚拟DOM
由浏览器的渲染流水线可知,DOM操作是一个昂贵的操作,很耗性能,因此产生了虚拟DOM。虚拟DOM是对真实DOM的映射,React通过新旧虚拟DOM对比,得到需要更新的部分,实现数据的增量更新
2、JSX是什么,它和JS有什么区别
JSX是react的语法糖,它允许在html中写JS,它不能被浏览器直接识别,需要通过webpack、babel之类的编译工具转换为JS执行
JSX与JS的区别:
JS可以被打包工具直接编译,不需要额外转换,jsx需要通过babel编译,它是React.createElement的语法糖,使用jsx等价于React.createElement
jsx是js的语法扩展,允许在html中写JS;JS是原生写法,需要通过script标签引入
3、简述React的生命周期
生命周期指的是组件实例从创建到销毁的流程,函数组件没有生命周期,只有类组件才有,因为只有class组件会创建组件实例
组件的生命周期可以分为挂载、更新、卸载阶段
挂载
constructor 可以进行state和props的初始化
static getDerivedStateFromProps
render
componentDidMount 第一次渲染后调用,可以访问DOM,进行异步请求和定时器、消息订阅
更新 当组件的props或state变化会触发更新
static getDerivedStateFromProps
shouldComponentUpdate 返回一个布尔值,默认返回true,可以通过这个生命周期钩子进行性能优化,确认不需要更新组件时调用
render
getSnapShotBeforeUpdate
componentDidUpdate 在组件完成更新后调用
卸载
componentWillUnmount 组件从DOM中被移除的时候调用
错误捕获
static getDerivedStateFromError 在errorBoundary中使用
componentDidCatch
render是class组件中唯一必须实现的方法
4、React事件处理为什么要手动绑定this
react组件会被编译为React.createElement,在createElement中,它的this丢失了,并不是由组件实例调用的,因此需要手动绑定this
??? 为什么不能通过return false阻止事件的默认行为
因为React基于浏览器的事件机制实现了一套自己的事件机制,和原生DOM事件不同,它采用了事件委托的思想,通过dispatch统一分发事件处理函数
5、类组件和函数组件之间的区别是什么?
1- 类组件可以使用其他特性,如状态和生命周期钩子,并且他有this
2- 函数组件只能接收props渲染到页面,无状态组件,没有this,不能使用生命周期钩子
3- 函数组件性能要高于类组件,因为类组件使用要实例化,而函数组件直接执行取返回结果即可,为了提高性能,尽量使用函数组件
6、react的优缺点
优点:
- 提高了应用性能和开发效率
- 使用JSX,代码可读性好
- react的componentWillUnmount生命周期,能够清除相关所有事件,避免内存泄露
- 并不直接对DOM进行操作,引入了一个虚拟DOM的概念,安插在js和真实DOM中间,性能好,速度快
缺点:
每次 state 更改,render 函数都要生成完整的虚拟 DOM. 哪怕 state 改动很小,render函数也会完整计算一遍。如果 render 函数很复杂,这个过程就白白浪费了很多计算资源
7、VUE与React两个框架的区别对比
相似之处:
用于创建UI的js库
使用起来轻快便捷
都用了虚拟DOM
都是基于组件的架构
不同点 :
vue使用的html模板;react使用的是js
vue有双向绑定语法
vue增加了语法糖computed和watch等,react需要自己写逻辑来实现
react用了jsx语法
react整体思路是编程式,推荐组件化,数据不变,单向数据流;vue数据可变,双向绑定,声明式的写法
8、React的工作原理以及阻止React的默认行为
React会创建一个虚拟的DOM。当一个组件的状态改变时,React首先会通过“diffing"算法来标记虚拟DOM中的改变,第二步是调节,会用diff的结果来更新DOM.
e.preventDefault(),e是第三方提供的一个合成事件(注意:不能用return)
9、React中diff算法
作用:用来计算VirtualDOM中被改变部分,针对该部分进行原生DOM操作,不用重新渲染整个页面
10、props和state
state是数据结构,只能使用setState来改变
props是组件的属性,由父组件传递给子组件,props是不可以改变的
state是局部的,除了它所在的这个组件其它组件都无法访问
11、React可以用两种方法声明组件,他们的区别是什么,什么情况你会选择哪一种?
函数组件:首字母大写,需要return出react元素
类组件:首字母大写,需要使用render方法,return出react元素
区别:
函数组件是无状态组件的思想
函数组件中不能用State,不能用组件的生命周期方法,这就决定了函数组件都是展开性组件,接收props,渲染DOM,而不关注其它逻辑
函数组件中没有this
函数组件更容易理解。当你看到一个函数组件时,你就知道它的功能只是接收属性,渲染页面,它不执行与UI无关的逻辑处理,它只是一个纯函数
12、React组件生命周期的阶段是什么?
组件的生命周期可分成三个状态:
Mounting:已载入真实 DOM
Updating:正在被重新渲染
Unmounting:已移出真实 DOM
13、调用setState之后发生了什么
setState会进行状态更新
将传入的参数对象与组件当前状态合并,然后触发所谓的调和过程,经过调和过程,根据新的state,React元素会重新构建虚拟DOM,进行diff算法对比新旧虚拟DOM树的区别,进行视图更新,而不是全部渲染
setState 采用的任务队列机制,不会马上执行,而是加入队列,在下次事件循环是一次性执行
(在构造函数中)调用 super(props) 的目的是什么
在super() 被调用之前,子类是不能使用 this 的,在 ES5 中,子类必须在 constructor 中调用 super()。传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props
为什么浏览器无法读取JSX?
浏览器只能处理JS对象,而不能读取常规的JSX。为了使浏览器能够读取JSX,首先,需要像Babel这样的JSX转换器将JSX转换为JS对象,然后再传给浏览器
14、什么是 Props?
只读组件,必须保持纯函数,即不可变。它们总是再整个应用中从父组件传递到子组件。子组件永远不能将prop送回到父组件。这有助于维护单向数据流,通常用于呈现动态生成的数据
15、React中的状态是什么?它是如何使用的?
是React 组件的核心,是数据的来源,必须尽可能简单。基本上状态是确定组件呈现和行为的对象。与props不同,它们是可变的,并创建动态和交互式组件。可以通过this.state()访问它们。
16、React中的合成事件是什么?
围绕浏览器原生事件充当跨浏览器对象。将不同浏览器的行为合并为一个 API。这样做是为了确保事件在不同浏览器中显示一致的属性
17、受控组件和非受控组件
受控组件:通过setState的形式控制输入的值及更新
非受控组件:通过dom的形式更新值,获取值通过ref的形式去获取
18、componentWillUpdate可以直接修改state的值吗
不可以,会导致无限循环报错
在react中直接修改state,render函数不会重新执行渲染,应使用setState方法进行修改
19、模仿vue中v-model指令,react实现类似双向绑定
通过onChange事件监听input的value值,在通过this.setState改变显示出来
20、react无状态组件和class类组件的区别
函数组件是一个返回react元素的函数,体现的是无状态组件思想,函数组件中没有this,没有state,没有生命周期,决定了函数组件都是展示性组件,接收props,渲染dom
函数组件不需要考虑组件状态和组件生命周期方法,有很大的性能提升空间
21、React中什么是纯函数
即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用。
22、setState是同步的还是异步的?
一、setState 并不是单纯同步/异步的,它的表现会因调用场景的不同而不同:
● 在 React 钩子函数及合成事件中,它表现为异步;
● 同步:
○ DOM 原生事件中(绕过React通过addEventListener直接添加的事件处理函数)
○ 通过setTimeout/setInterval产生的异步调用
23、类组件和函数组件之间的区别是什么?
类组件可以使用其他特性,如状态和生命周期钩子,并且他有this
函数组件只能接收props渲染到页面,无状态组件,没有this,不能使用生命周期钩子
函数组件性能要高于类组件,因为类组件使用要实例化,而函数组件直接执行取返回结果即可,为了提高性能,尽量使用函数组件
24、react中refs是什么?
refs是提供一种访问在render方法中创建DOM节点或者React元素的方法,在典型的数据流中,props是父子组件交互的唯一方式,想要修改子组件,需要使用新的props重新渲染它,某些情况下,在典型的数据流外,强制修改子代,这个时候可以使用refs
我们可以在组件添加一个ref属性来使用,该属性是一个回调函数,接收作为其第一个参数的底层DOM元素或组件挂载实例
input元素有一个ref属性,他的值是一个函数,该函数接收输入的实际DOM元素,然后将其放在实例上,这样就可以在 handleSubmit 函数内部访问它
经常被误解的只有在类组件中才能使用 refs,但是refs也可以通过利用 JS 中的闭包与函数组件一起使用
25、state和props区别是什么?
相同点:都是普通的js对象,他们包含着影响渲染输出的信息
不同点:state是组件自己管理数据,控制自己的状态,可变
props是外部传入的数据参数,不可变
没有state的叫做无状态组件,有state的叫有状态组件
多用props,少用state
63.在构造函数调用super并将props作为参数传入的作用是啥?
在调用 super() 方法之前,子类构造函数无法使用this引用,ES6 子类也是如此。将 props 参数传递给 super() 调用的主要原因是在子构造函数中能够通过this.props来获取传入的 props。
props 的行为只有在构造函数中是不同的,在构造函数之外也是一样的
26、什么是jsx?
在第一发布react时,还引入了一种新的js方言jsx,将原始 HTML 模板嵌入到 JS 代码中。JSX 代码本身不能被浏览器读取,必须使用Babel和webpack等工具将其转换为传统的JS。很多开发人员就能无意识使用 JSX,因为它已经与 React 结合在一起了
27、什么是React 路由
React 路由是一个构建在 React 之上的强大的路由库,它有助于向应用程序添加新的屏幕和流。这使 URL 与网页上显示的数据保持同步。它负责维护标准化的结构和行为,并用于开发单页 Web 应用。 React 路由有一个简单的API
28、React有什么特点
React的主要功能如下:
它使用虚拟DOM 而不是真正的DOM。
它可以进行服务器端渲染。
它遵循单向数据流或数据绑定。
29、列出React的一些主要优点
它提高了应用的性能
可以方便地在客户端和服务器端使用
由于 JSX,代码的可读性很好
React 很容易与 Meteor,Angular 等其他框架集成
使用React,编写UI测试用例变得非常容易
30、当调用setState时,React render 是如何工作的
虚拟 DOM 渲染:当render方法被调用时,它返回一个新的组件的虚拟 DOM 结构。当调用setState()时,render会被再次调用,因为默认情况下shouldComponentUpdate总是返回true,所以默认情况下 React 是没有优化的。
原生 DOM 渲染:React 只会在虚拟DOM中修改真实DOM节点,而且修改的次数非常少——这是很棒的React特性,它优化了真实DOM的变化,使React变得更快。
31、如何避免组件的重新渲染?
React 中最常见的问题之一是组件不必要地重新渲染。React 提供了两个方法,在这些情况下非常有用:
React.memo():这可以防止不必要地重新渲染函数组件
PureComponent:这可以防止不必要地重新渲染类组件
这两种方法都依赖于对传递给组件的props的浅比较,如果 props 没有改变,那么组件将不会重新渲染。虽然这两种工具都非常有用,但是浅比较会带来额外的性能损失,因此如果使用不当,这两种方法都会对性能产生负面影响。
通过使用 React Profiler,可以在使用这些方法前后对性能进行测量,从而确保通过进行给定的更改来实际改进性能。
32、React中的状态是什么?它是如何使用的?
状态是 React 组件的核心,是数据的来源,必须尽可能简单。基本上状态是确定组件呈现和行为的对象。与props 不同,它们是可变的,并创建动态和交互式组件。可以通过 this.state() 访问它们
33、React 中 key 的重要性是什么?
key 用于识别唯一的 Virtual DOM 元素及其驱动 UI 的相应数据。它们通过回收 DOM 中当前所有的元素来帮助 React 优化渲染。这些 key 必须是唯一的数字或字符串,React 只是重新排序元素而不是重新渲染它们。这可以提高应用程序的性能
34、模块与组件、模块化与组件化的理解
模块
理解:向外提供特定功能的js程序, 一般就是一个js文件
为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂。
作用:复用js, 简化js的编写, 提高js运行效率
组件
理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image等等)
为什么要用组件: 一个界面的功能更复杂
作用:复用编码, 简化项目编码, 提高运行效率
模块化:当应用的js都以模块来编写的, 这个应用就是一个模块化的应用
组件化:当应用是以多组件的方式实现, 这个应用就是一个组件化的应用
35、如何在 Redux 中定义 Action
React 中的 Action 必须具有 type 属性,该属性指示正在执行的 ACTION 的类型。必须将它们定义为字符串常量,并且还可以向其添加更多的属性。在 Redux 中,action 被名为 Action Creators 的函数所创建
36、Redux 有哪些优点?
Redux 的优点如下:
结果的可预测性 - 由于总是存在一个真实来源,即 store ,因此不存在如何将当前状态与动作和应用的其他部分同步的问题。
可维护性 - 代码变得更容易维护,具有可预测的结果和严格的结构。
服务器端渲染 - 你只需将服务器上创建的 store 传到客户端即可。这对初始渲染非常有用,并且可以优化应用性能,从而提供更好的用户体验。
开发人员工具 - 从操作到状态更改,开发人员可以实时跟踪应用中发生的所有事情。
社区和生态系统 - Redux 背后有一个巨大的社区,这使得它更加迷人。一个由才华横溢的人组成的大型社区为库的改进做出了贡献,并开发了各种应用。
易于测试 - Redux 的代码主要是小巧、纯粹和独立的功能。这使代码可测试且独立。
组织 - Redux 准确地说明了代码的组织方式,这使得代码在团队使用时更加一致和简单
37、react中ref的使用方式?
可以直接写一个字符串,不过它只适用于类组件
createRef和useRef来定义ref变量,ref.current获取数据
可以使用箭头函数的方式,提前定义一个变量,箭头函数的形参就是当前对象
38、怎样解释 React 中 render() 的目的
每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如 <form>、<group>、<p> 等。此函数必须保持纯净,即必须每次调用时都返回相同的结果
39、Store 在 Redux 中的意义是什么
Store 是一个 JavaScript 对象,它可以保存程序的状态,并提供一些方法来访问状态、调度操作和注册侦听器。应用程序的整个状态/对象树保存在单一存储中。因此,Redux 非常简单且是可预测的。我们可以将中间件传递到 store 来处理数据,并记录改变存储状态的各种操作。所有操作都通过 reducer 返回一个新状态。
40、为什么浏览器无法读取JSX?
浏览器只能处理 JavaScript 对象,而不能读取常规 JavaScript 对象中的 JSX。所以为了使浏览器能够读取 JSX,首先,需要用像 Babel 这样的 JSX 转换器将 JSX 文件转换为 JavaScript 对象,然后再将其传给浏览器
41、Redux遵循的三个原则是什么?
单一事实来源:整个应用的状态存储在单个 store 中的对象/状态树里。单一状态树可以更容易地跟踪随时间的变化,并调试或检查应用程序。
状态是只读的:改变状态的唯一方法是去触发一个动作。动作是描述变化的普通 JS 对象。就像 state 是数据的最小表示一样,该操作是对数据更改的最小表示。
使用纯函数进行更改:为了指定状态树如何通过操作进行转换,你需要纯函数。纯函数是那些返回值仅取决于其参数值的函数。
42、解释 Reducer 的作用
Reducers 是纯函数,它规定应用程序的状态怎样因响应 ACTION 而改变。Reducers 通过接受先前的状态和 action 来工作,然后它返回一个新的状态。它根据操作的类型确定需要执行哪种更新,然后返回新的值。如果不需要完成任务,它会返回原来的状态
更多推荐
所有评论(0)