测试终端的操作(端面试题总结)
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.$emit5- 选项式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接收自定义事件 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- hash与history的区别
1.hash模式带#号比较丑 ,history模式比较优雅;
2.pushState设置的新的URL可以是与当前URL同源的任意URL;而hash只可修改#后面的部分 ,故只可设置与当前同文档的URL;
3.pushState设置的新URL可以与当前URL一模一样 ,这样也会把记录添加到栈中;而hash设置的新值必须与原来不一样才会触发记录添加到栈中;
4.pushState通过stateObject可以添加任意类型的数据到记录中;而hash只可添加短字符串;
5.pushState可额外设置title属性供后续使用;
6.hash兼容IE8以上,history兼容IE10以上;
7.history模式需要后端配合将所有访问都指向index.html ,否则用户刷新页面 ,会导致404错误 。9- 导航守卫 函数 以及参数的作用
全局前置守卫:beforeEach
全局解析守卫:beforeResolve
全局后置钩子:afterEach
路由独享守卫:beforeEnter
组件内—进入:beforeRouteEnter
组件内—更新:beforeRouteUpdate
组件内—离开:beforeRouteLeave
里面的三个参数:
to : 即将要进入的目标 路由对象
from : 当前导航正要离开的路由
next() 通过调用next方法 才会进入到目标路由对象
Next()默认参数为:
True:允许跳转,
False: 拒绝跳转 ,
路由路径: 跳转到该路径
函数:在跳转前进行逻辑处理 ,从而决定是否跳转 。
函数内的参数可以获取到组件的实例;10- watch与watchEffect的区别
与 watchEffect() 相比,watch() 使我们可以:懒执行副作用:watch是懒侦听执行的;watchEffect是首次就会执行
触发侦听器的来源:watch是明确知道由哪个依赖引起的侦听 ,watchEffect不明确
可以访问所侦听状态的前一个值和当前值:watch可以 ,watchEffect不可以 。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请求 ,可以在地址栏看到参数
params1.是路由的一部分 。以对象的形式传递参数
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 、routej与router的区别
$route:获取路由信息 指当前路由实例跳转到的路由对象
包括:
$route.path 字符串 ,等于当前路由对象的路径 ,会被解析为绝对路径 ,如/home/ews
$route.name 当前路由的名字 ,如果没有使用具体路径 ,则名字为空
$route.router 路由规则所属的路由器
$route.matchd 数组 ,包含当前匹配的路径中所包含的所有片段所对象的配置参数对
象
$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 、hooks
-- 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)的参数el38 、数据代理
通过一个对象代理另一个对象中属性的操作(读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 ,所有的页面内容都包含在主页面中) ,页面复杂度提高了 ,导航不
可用ES6
1- 写出对promise的理解
Promise是异步编程的一种解决方案 ,比传统的解决方案——回调函数和事件——更合理和更强大 。所谓Promise ,简单说就是一个容器 ,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果 。
通俗讲,Promise是一个许诺 、承诺,是对未来事情的承诺 ,承诺不一定能完成 ,但是无论是否能完成都会有一个结果 。
Pending 正在做 。 。。
Resolved 完成这个承诺
Rejected 这个承诺没有完成,失败了
Promise 用来预定一个不一定能完成的任务 ,要么成功 ,要么失败
在具体的程序中具体的体现,通常用来封装一个异步任务 ,提供承诺结果
Promise 是异步编程的一种解决方案 ,主要用来解决回调地狱的问题 ,可以有效的减少回调嵌套 。真正解决需要配合async/await2- 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 值,作为自己的
thisjavaScript
1什么是原型与原型链
原型
JS声明构造函数(用来实例化对象的函数)时 ,会在内存中创建一个对应的对象 ,这个对象就是原函数的原型。构造函数默认有一个prototype属性,prototype的值指向函数的原型 。同时原型中也有一个constructor属性 ,constructor的值指向函数对象 。
通过构造函数实例化出来的对象 ,并不具有prototype属性 ,其默认有一个__proto__属性 ,__proto__的值指向构造函数的原型 。在原型对象上添加或修改的属性 ,在所有实例化出的对象上都可共享 。
原型的作用:1.数据共享 节约内存内存空间
2.实现继承
原型链当在实例化的对象中访问一个属性时 ,首先会在该对象内部(自身属性)寻找 ,如找不到 ,则会向其__proto__指向的原型中寻找 ,如仍找不到,则继续向原型中__proto__指向的上级原型中寻找 ,直至找到或Object.prototype.__proto__为止(值为null) ,这种链状过程即为原型链 。如下图所示好理解(根据代码参考下图)
原型链的作用:查找对象的属性(方法)
(了解)
Object.prototype.constructor.proto === Function.prototype // trueFunction.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的长%E创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!