this指向
除了箭头函数,和函数的定义无关,和函数的调用有关。
- 直接调用,this指向window,严格模式下指向undefined
- 谁调用指向谁
- new,this指向实例
- 箭头函数的this指向上下文
改变this指向的方法
- fn.call(this指向的,函数需要的实参)
- fn.apply(this指向的,[函数需要的实参])
- fn.bind(this指向的),bind不会调用函数,而是根据该函数生成一个新函数,并且新函数的this指向了()的对象
异步
js 是单线程的,也就代表 js 只能一件事情一件事情执行,那如果一件事情执行时间太久,后面要执行的就需要等待,需要等前面的事情执行完成,后面的才会执行。
所以为了解决这个问题,js 委托宿主环境(浏览器)帮忙执行耗时的任务,执行完成后,在通知 js 去执行回调函数,而宿主环境帮我们执行的这些耗时任务也就是异步任务
js 本身是无法发起异步的,是委托给宿主环境发起异步的,但是 es5 之后提出了 Promise 可以进行异步操作
--执行流程如下:
主线程先判断任务类型
- 如果是同步任务,主线程自己执行
- 如果是异步任务,交给宿主环境(浏览器)执行
宿主环境进行异步任务的执行,每个异步执行完后,会将回调放进任务队列,先执行完成的先放进任务队列。
等主线程任务全部执行完后,会取任务队列中的任务,根据先进先出原则
在任务队列中取出来的任务,会回到主线程执行,执行完成后,在取下一个,依次重复,这个过程也称为 eventLoop 事件轮训
--而我们所提道的异步任务,也分为宏任务和微任务。
由宿主环境发起的异步被称为宏任务。(setTimeOut、setInterval)
由js自身发起的异步被称为微任务。(promise)
(判断由谁发起的,看是否是ecma的,如果是,则表示是js自身发起的。也就被称为微任务。但是我们用到的微任务基本只有promise————还有一个特殊情况MutationObserver,虽然是由web发起的,但是也是微任务)
promise不是异步的,(.then)才是异步的微任务
await下面的也可以看作是微任务
--执行顺序
- 先执行宏任务(将整个script标签的代码段看作是一次宏任务)----同步任务
- 宏任务执行完后看微任务队列是否有微任务
- 没有微任务执行下一个宏任务
- 有微任务将所有微任务执行
- 执行完微任务,执行下一个宏任务
解决异步,最常用的就是promise
computed和watch的区别
计算属性computed:
- 支持缓存,只有依赖数据发生改变,才会重新进行计算
- 不支持异步,因为有return的存在
- 定义的时候是方法,使用的是属性
侦听属性watch:
- 不支持缓存,数据变,直接会触发相应的操作
- watch支持异步
- 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
- watch可以监视:props\data\computed\$route
- 监视的是一个对象: 开启深度监听 deep:true
动态路由和静态路由
静态路由是管理员手动配置的,不便于拓展网络拓扑结构,一但网络拓扑发生改变,静态路由配置量会很大。动态路由是路由器通过网络协议,动态的学习路由,当网络拓扑发生变化的时候,路由器会根据路由协议自动学习新的路由。
动态路由,因为OSPF,RIP等路由协议都会有周期更新,所以更新量大,占用宽带大。
使用静态路由的好处是网络安全保密性高。动态路由因为路由器之间频繁交替,需要经常使用路由表,而路由表可以分析出拓扑结构和网络地址等,所以安全性低。
动态路由:灵活性高
静态路由:安全,占用宽带小,简单,高效。
路由传参
- 动态路由传参
- 路由配置,需要在path上进行参数设置
- params方法 path: '/xxx/:uid',
- query方法 path: '/xxx?uid=值',
- 路由跳转,this.$router.push('地址');
- 在对应页面中拿到路由参数,this.$route.params.uid / this.$route.query.uid;
- query方式传参
- 路由配置不变
- 路由跳转
- 用path跳转,this.$router.push(),参数为对象,path:对应路由配置的值,query参数
- 用name跳转,this.$router.push(),参数为对象,name:对应路由配置的值,query参数
- 在对应页面中拿到路由参数,this.$route.query.uid;
- params方式传参,只能通过name跳转
- 路由配置不变
- 路由跳转,this.$router.push(),参数为对象,name:对应路由配置的值,params参数
- 在对应页面中拿到路由参数,this.$route.params.uid;
页面跳转的方法:
1、<router-link to="需要跳转到页面的路径">
2、this.$router.push()跳转到指定的url,并在history中添加记录,点击回退返回到上一个页面
3、this.$router.replace()跳转到指定的url,但是history中不会添加记录,点击回退到上上个页面
4、this.$router.go(n)向前或者后跳转n个页面,n可以是正数也可以是负数
路由守卫
路由守卫分为三种,全局守卫,路由独享守卫以及组件内守卫。
全局守卫
- 全局前置守卫
- 写法router.beforeEach()
- 每一个路由进入前触发
- 可以用来进行路由权限的控制。
- 在回调中有三个参数,to,from,next,其中next()必写。
- 全局后置守卫
- 写法router.afterEach()
- 每一个路由进入后触发
- 用于提示语之类的
路由独享守卫
- 写法beforeEnter(),写在路由规则配置里面,和path,name同级
- 单独进入某个路由前触发
- 在回调中有三个参数,to,from,next,其中next()必写
组件内守卫
- 写在组件内,和created等生命周期同级
- 在回调中有三个参数,to,from,next
- 写法有三个
-
- beforeRouteEnter
-
-
- 渲染组件前触发
- 不能获取组件实例 `this`
-
-
- beforeRouteUpdate
-
-
- 在当前路由改变,但是该组件被复用时调用
- 一般就是是同一个页面,不同的参数这样,此时组件复用,没有被创建,也就无法重新创建。
- 可以访问组件实例 `this`
-
-
- beforeRouteLeave:路由离开
-
-
- 路由离开时调用
- 可以访问组件实例 `this`
- 比如在编辑过程中,要离开给页面,就会跳出没有保存,是否需要离开的提示。
-
聊聊vuex
对于vuex的话。
vuex是一个状态管理的库,是用来实现组件之间的数据共享的。
vuex的优点是数据的响应式,可以便于数据的传递,方便维护和管理。
vuex包含了5个属性:
state,用于定义和存储共享的数据。用$store.state或者是辅助函数mapState来进行触发。
mutations,用来修改数据,也是修改数据的唯一来源。(当然,其实state数据是可以直接进行赋值修改的,但是并不建议使用,就像是所有人都可以更改公司数据一样,存在着各种不安全隐患。)用commit或者辅助函数mapmutations来进行触发修改数据。
actions:说道actions,就要提到刚刚说的mutations,mutations的同步的,而actions是异步的。用dispatch或者是辅助函数mapactions来触发。但是actions只能够进行异步处理,不能修改state的数据。所以如果需要修改数据,还是需要调用mutations来处理。
所以我们的同步流程就是直接触发mutations,而异步流程则是先触发actions,再由actions进行异步处理以后再去触发mutations。
getters:基于state进行派生数据
moudles:模块化,将数据模块化后,会有上述的四种属性。模块化后的数据方便维护和管理。每一个模块可以设置命名空间,如果不设置,那么mutations和actions的使用和全局并无差别。如果开启命名空间,则需要通过模块名进行访问。
vuex的缺点就是不能持久化。我们在使用的时候,如果数据是从后台请求回来的,那么可以直接忽略持久化的问题。如果不是请求回来的,那么就需要解决持久化的问题。
解决的方式就是本地存储。除了localStorage, sessionStorage, cookie以外,我们还常用一个自动存储的插件
vuex-persistedstate。
mutations是处理同步的数据的,如果处理异步的话,会导致devtool的记录出现问题,也就无法及时的知道状态是何时更新的,无法追踪状态,给调试带来困难。那我们公司就是不管同步还是异步,都会先进行一个actions的异步处理,再去调用mutations来处理修改数据。
vue.use()的原理
通过全局方法vue.use()使用插件
Vue.use会自动阻止多次注册相同插件
需要在调用new Vue()启动应用之前完成
Vue. use()至少传入一个参数
如果参数是一个Object对象,那么这个对象必须提供一个install函数
如果参数是一个function函数,那么就相当于install函数
Vue. use()的其他参数,都会依次传给install函数
install函数默认的第一个参数是vue,后面的参数来自于Vue.use后续参数
vue.use本质是无法注册全局组件或者给vue原型添加方法的,但是我们在使用路由或者vuex或者element ui,实际还是在install函数内部通过vue.component注册了全局组件或者给Vvue.prototype手动添加方法。
v-if和v-show
v-show和v-if都是可以用来控制元素的隐藏和显示的。true的时候表示显示,false的时候表示隐藏。
v-show的隐藏使用的是css样式display:none的方式,不管是true还是false,它都会渲染对应的dom元素。
优点:不会频繁创建dom
缺点:首次渲染为false也会创建
场景:适用于频繁切换的场景。
v-if的隐藏是直接从dom上移出,不会产生对应的元素。在true的时候,再创建相对应的整个标签。
优点:他是懒渲染,默认首次如果是false,元素不会创建。如果是组件,利用v-if可以重新触发生命周期
缺点:频繁的删除和重建
场景:适用于一进入页面,就确定是显示和隐藏,后期不会改变的场景。
或者组件需要重新触发生命周期的场景
v-if还有一个v-show没有的高级语法,就是和v-else搭配使用的判断条件的用法。
$route和$router
$route:用来获取当前路由信息的,每个路由都会有一个$route对象,是一个局部的对象
可以写作$route.path(当前路径)params,name等
$router:全局路由实例,用来操作路由的
等价于 new VueRouter
包含所有的路由,路由的跳转方式,钩子函数等等。
最常用的就是this.$router.push()进行跳转
v-model
作用:一是数据双向绑定,二是实现组件通信
原理:v-model就是一个语法糖,动态绑定了value和注册了input事件
使用场景:
- 一是在表单中使用,比如input输入框之类的,需要双向绑定这个数据,就可以绑定一个v-model,绑定的就是input内输入的值
- 二是在组件上使用,在组件上使用的情况就是:父组件数据要传给子组件,并且子组件需要修改数据(两件事情都需要的情况下才会使用)
缺点:v-model在一个组件上只能使用一次
MVVM 的设计思想的优势
- mvc的改进版
- 双向绑定技术,当 数据变化时,视图也会自动变化,视图发生更新,数据也跟着同步
- 我们减少了 dom 的操作,因为我们只需要关注数据就可以
- mvvm 的设计思想大大提高了代码的耦合性
- 数据响应式的原理
keep-alive
keep-alive是一个内置组件,它会缓存不活动的组件实例,而不是将其销毁。不会渲染dom元素
它提供了include和exclude属性。
它包含了activated和deactivated钩子函数
include:指定缓存的组件
exclude:指定不缓存的组件
activate:激活状态
deactivated:失去激活状态
图片懒加载
图片懒加载的原理:优先加载可视区域的内容,其他部分等进入了可视区域再加载,从而提高性能。
一张图片就是一个<img>标签,浏览器是否发起请求图片是根据<img>的src属性,所以实现懒加载的关键就是,在图片没有进入可视区域时,先不给<img>的src赋值,这样浏览器就不会发送请求了,等到图片进入可视区域再给src赋值。
虚拟dom和diff算法
虚拟dom的本质就是一个js对象,用来描述真实dom是什么样子的,这个对象就是我们常说的虚拟dom。
虚拟dom的出现可以进行高效更新,同时可以使用虚拟dom进行跨平台。
我们在初始化渲染的时候,会根据数据和模板生成一个虚拟dom树,当数据发生变化的时候,又会根据新的数据和模板,生成一个新的虚拟dom树。然后将新旧两颗虚拟dom树进行对比。对比的过程使用的就是diff算法。说道diff算法。它的特点是同级比较,深度优先,且采用双指针算法。这里的双指针算法会产生四个指针,新旧虚拟dom树各有两根指针,都是一个指向开始位置,一个指向结束位置。在进行循环的时候,开始位置的指针会在对比完以后向后推,结束位置的指针在对比玩以后会向前推,从而达到高效更新。
diff对比情况分为三种。
一是元素不同,会直接删除重建。
二是元素相同,属性不同,那么元素会进行复用,只会更新属性。
三是v-for循环的情况。这也会分成两种,
一是没有key的时候,如果数据的变化没有影响到顺序,那么性能没有影响。如果数据的变化影响到了顺序,那么性能也会受到影响。因为没有key的时候,我们是根据顺序进行对比的。
二是有key的时候,key是不建议使用索引的,因为索引是会变化的。我们推荐使用唯一值,对比的使用会根据key值进行对比。
路由模式
路由模式分为三种
- abstract,支持所有 JavaScript 运行环境,如果发现没有浏览器的 API,路由会自动强制进入这个模式。
- hash模式:
-
- 有#/,
- 通过window.location.href进行跳转
- 通过window.onhashchange进行监听
- history模式:(推荐使用)
-
- 没有#/
- 通过history.pushState和history.repleaceState进行跳转,
- 通过onpopState进行监听,只能监听前进和后退,无法监听history.pushState和history.repleaceState, 源码中将history.pushState和history.repleaceState,进行了统一的包装,通过pushState函数进行包装,不管是history.pushState还是history.repleaceState实际底层最终都会通过pushState这个函数进行跳转,通过pushState进行监听
- 刷新会404,需要后端的支持。
环境变量
一个项目在开发的过程中,会经历各种过程才会发布,每个过程的环境不同,就会需要不同的配置参数,所以就可以用环境变量来方便我们管理。
每个不同的环境有一个不同的文件,这些文件都和src同级
一个项目,基准地址(环境)会有3套,分别是开发期间的、测试的、线上的
在package.json中会有相对应的配置,运行不同的命令代表不同的环境,使用的就是不同文件内,环境变量的值。
环境变量是存放基准地址的,不同的环境(比如测试,开发期间,上线等)的基准地址可能会不同。用环境变量来存储。环境变量的值来自于不同的环境文件.env.的文件中
nextTick
作用:数据发生变化后,可以利用nextTick获取最新的视图
原理:数据发生变化会驱动视图,这是一个异步操作。为了性能,等所有数据变化后,进行合并更新视图。因为这个原因,导致数据发生变化后,无法立即获取最新视图。
解决方案就是使用nextTick
nextTick不传回调的时候,则内部是promise对象
nextTick传回调的时候,则内部是setTimeout定时器
token过期问题
token一般的过期时间是2个小时。这里要引入一个其他内容,refresh_token过期时间较长(一周、两周)
在token过期的时候,我们会在用户不知情的情况下,偷偷的发送一个请求,获取新的token。通过refresh__token偷偷进行换取,登录状态就可以继续维持一周到两周。如果refresh__token也过期了,那么就会跳转到登录页,需要重新进行登录。
如何判断token过期
1、前端主动处理
当判断token过期时候,不再发送请求,就可以优化性能。减少网络请求的次数
借助时间戳:
登录成功的时候存下token的时间戳
发送请求前,获取当前的时间戳-存下token的时间戳,等到的值如果超过了token的有效期(两个小时),那么就不发送请求,而是跳转到登录页面,要求重新登录。
2、前端被动处理,由后端主动处理。也就是需要判断请求的时候,返回的状态码,一般401是登录过期,也就是token过期的情况(当然具体是要看后端的返回,这里的401只是一般情况下)
.sync修饰符
修饰符有哪些:
v-on的
- .stop - 阻止事件冒泡
- .prevent - 阻止默认行为
- .once - 程序运行期间, 只触发一次事件处理函数(不可以和其他修饰符连用)
- .native - 在某个组件的根元素上监听一个原生事件
v-model的
- .number 以parseFloat转成数字类型
- .trim 去除首尾空白字符
- .lazy 在change时触发而非inupt时
作用: 语法糖,也可以实现组件通信, 类似双向绑定(父向子传,子向父改)
原理: .sync解析出一个动态绑定的数据,解析一个自定义事件,@update:属性名,组件内部可以通过this.$emit('update:属性名的')进行触发
.sync: 可以使用多次, 而且.sync可以和v-bind结合直接传递一个对象,将对象的每个属性单独传递进去,单独的绑定v-on事件
:属性名.sync=‘变量’
等价于
:属性名=‘变量’(父向子传值)
@update:属性名=‘变量=$event’(@update表示自定义事件)
首屏优化
- soucemap: 关闭
- 路由懒加载
- cdn资源
- splitChunks: 提取公共资源
- 图片压缩
- gzip
- runtimeChunks
- ssr: 服务端渲染
- 解决首屏加载速度慢的问题,因为首屏服务端直接返回,不需要加载js文件
- 还可以解决seo,html不再是只有一个id为app的标签,更加有利于seo搜索
- 实现ssr的方法是使用vue结合nuxt
spa单页面应用
我们vue是使用spa的,spa页面响应速度快,可以减轻服务器压力,但是不利于seo,首屏加载也会比较慢。
这时候就会用到ssr。也就是在vue中使用nuxt框架。虽然可以让爬虫更容易爬到数据,响应速度也更快,但是会增加服务器的压力,并且开发的难度也比较大。
封装创建组件
(1)组件封装思想
- 组件的结构:结构考虑复用灵活,一般使用插槽、允许自定义
- 组件的样式:考虑支持自定义,一般使用属性传值(通过样式或者类名)
- 组件的数据:通过数据传递
- 暴露事件:例如弹框组件,点击遮罩弹框关闭,用户使用组件的时候,也需要监听到点击遮罩的行为,用户可以进行自定义的逻辑
(2)如何创建一个全局组件
通过 Vue.component 来创建一个全局组件,第一个参数是组件名字,第二个参数是组件的配置对象,可以通过 template 配置组件的结构,data 定义数据等等
(3)如何创建一个局部组件
在组件内部通过 components 来创建一个局部组件
全局组件和局部组件的区别
局部组件:只能在当前的父组件中使用
全局组件: 在任意地方使用
(4)如何定义局部自定义指令
在组件内部通过 directives 来创建一个局部指令
全局指令和局部指令的区别
局部指令:只能在当前的组件中使用
全局指令: 在任意地方使用
(5)如何定义局部过滤器
在组件内部通过 filters 来创建一个局部过滤器
全局过滤器和局部过滤器的区别
局部过滤器:只能在当前的组件中使用
全局过滤器: 在任意地方使用
link与@import的区别是什么
1、从属关系区别
@import是 CSS 提供的语法规则,只有导入样式表的作用;link是HTML提供的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等。
2、加载顺序区别
加载页面时,link标签引入的 CSS 被同时加载;@import引入的 CSS 将在页面加载完毕后被加载。
3、兼容性区别
@import是 CSS2.1 才有的语法,故只可在 IE5+ 才能识别;link标签作为 HTML 元素,不存在兼容性问题。
4、DOM可控性区别
可以通过 JS 操作 DOM ,插入link标签来改变样式;由于 DOM 方法是基于文档的,无法使用@import的方式插入样式。
双向数据绑定
数据发生变化,同步视图,视图发生变化,同步数据。
v-model可以完成数据双向绑定。
但原理是v-on绑定事件和v-bind绑定数据,是一个语法糖。
v-bind可以实现数据变同步视图,这是因为数据响应式的原理。
v-on绑定事件可以实现视图变同步数据,这是数据响应式的原理。
是单向数据流?
在父向子传值的时候,如果改变父组件的值,子组件会跟着同步更新,反之不允许
自定义指令:
当vue 提供的系统指令满足不了我们的需求时,我们就需要自定义指令
全局通过 Vue.directive 进行自定义指令的定义。
局部通过directives进行定义。key为自定义指令的名字,value为对象,对象内有下面三个钩子函数。
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
- update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
vue 的两个核心
组件系统、数据驱动
组件插槽
- 默认插槽:
-
- 在组件标签中间可以传递一些子节点
- 组件内部利用 slot 标签进行接收
- 具名插槽(可以传多个插槽)
-
- 在组件标签中间通过定义 slot 的名字传递子节点
<my-banner> <div slot="header"> 头部 </div> <div slot="footer"> 底部 </div> </my-banner>
-
- 组件内部利用 slot 的 name 进行对应接收
<template id="banner"> <div> <slot name="header"></slot> <slot name="footer"></slot> </div> </template>
- 作用域插槽
-
- 在组件内部定义数据,将数据传递给插槽的结构
- 通过给 slot 动态绑定属性
<template id="my-li"> <ul> <li v-for="item in arr"> <slot :row="item"></slot> </li> </ul> </template>
-
- 插槽内部:通过 slot-scope=“scope”来接收
<my-li> <template slot-scope="scope"> <p>{{scope.row}}</p> </template> </my-li> <my-li> <template slot-scope="scope"> <a href="04-侦听器.html">{{scope.row}}</a> </template> </my-li>
vue 单页面应用的优缺点
缺点:
- 不利于 seo
- 兼容到 ie9
- 初次加载耗时相对增多
优点
- 用户体验好,不用重新刷新整个页面
- 前后端分离
- mvvm 设计模式
- 减轻服务期压力,只需要服务器提供数据
v-if和v-for为什么避免同时使用
v2中:
v-for的优先级高于v-if,所以还是会先循环创建虚拟dom,再利用v-if进行移除
解决方式:
- v-if写到外层
- 先通过计算属性将数据计算好
v3中: v-if优先级高
mock假数据
现在的项目都是前后端分离的,在前后端同时开发的过程中,后端接口数据没有出来,前端可以使用mock假数据。
优点:
团队可以并行工作。更好的进行前后端分离。
增加测试的真实性,通过随机数据,模拟各种场景。
开发无侵入,不需要修改既有代码,就可以拦截ajax请求,返回模拟的响应数据。
数据类型丰富,支持生成随机的文本、数字、布尔值、日期、邮箱、链接、图片、颜色等。
方便扩展,支持扩展更多数据类型,支持自定义函数和正则。
不涉及跨域问题
mixins
mixins: 将组件中的逻辑功能进行复用,复用部分可以提取到一个js文件中,然后通过mixins这个选项将该文件中暴漏的对象进行混入即可
可以混入哪些: 正常的实例对象一样包含实例选项,这些选项将会被合并到最终的选项中
优先级:
- 生命周期:组件和混入的都会调用(混入的先调用)
- data数据::进行合并,发生冲突以组件为主,mixins中的会被覆盖
- methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对
axios取消重复请求
- 场景:如果在输入框中输入12,然后先发1的请求,再发12的请求,但是如果关键词1的请求响应慢,12请求的数据先回来,那么1请求回来的数据会覆盖12的数据。和我们所需要的结果产生了出入。
- 解决方案:使用取消请求的方式。
- 原生的ajax可以使用abort()
- 取消axios请求,则使用axios内部的cancelToken方法
防抖和节流
防抖和节流都是为了避免函数被多次调用导致页面调用,但它们的本质不一样,防抖是将多次执行变为最后一次执行,节流是将多次执行变为每个一段时间执行一次。
防抖是指触发事件函数后,函数在n秒后只能执行依稀,如果n秒内再次触发,会重新计算时间。也就说说连续触发,只执行最后一次。
场景:
- 搜索框搜索输入,只需要用户最后一次输入完成,再发送请求。
节流会限制一个函数在n秒内只能执行一次,过了n秒又可以执行一次。
场景:
- 发送验证码的时候,60秒内只能发送一次。
假值有哪些
假值就是值boolean转出来是false的
- 0
- Null
- NaN
- False
- undefined
- 空字符串
get和post的区别
- 从标准上来说:
GET 用于获取信息,是无副作用的,是幂等的,且可缓存 ,安全性差
POST 用于修改服务器上的数据,有副作用,非幂等,不可缓存
- 从请求报文上来说:
GET 和 POST 只是 HTTP 协议中两种请求方式(异曲同工),而 HTTP 协议是基于 TCP/IP 的应用层协议,无论 GET 还是 POST,用的都是同一个传输层协议,所以在传输上,没有区别。
在报文格式上,不带参数时,基本一致,带参数时,在约定中,GET 方法的参数应该放在 url 中,POST 方法参数应该放在 body 中。
响应拦截器里面都做什么事情
- 请求拦截器
在请求发送前进行必要操作处理,例如添加统一cookie、请求体加验证、设置请求头等,相当于是对每个接口里相同操作的一个封装; - 响应拦截器
同理,响应拦截器也是如此功能,只是在请求得到响应之后,对响应体的一些处理,通常是数据统一处理等,也常来判断登录失效等。
实现实时更新
websocket
比如直播间弹幕啊,股票的实时数据更新,进入页面客服的自动发送信息等等
websocket是一种数据通信协议,常见的是http协议。
http协议的缺陷:通信只能由客户端发起,http基于请求响应实现。
vue 组件中的 data 为什么是一个函数,返回一个对象?
如果不是一个函数返回一个新的对象,组件如果多次使用,实际公用的是同一个数据
但是如果是通过函数 返回一个新的对象,这样的话,每个组件的使用数据是独立的
浅谈事件冒泡和事件捕获
事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题。
阻止事件冒泡e.stopPropagation()
简单来说,当你鼠标在浏览器上点击了一下。
- 浏览器捕获到了click事件。
- 然后浏览器根据你点击的事件,从window开始向下,就会触发每个父祖element捕获模式的事件回调。
- 直到找到点击所在的最终(最小的element)
- 然后浏览器开始继续又向上冒泡其父祖element的click事件,直至window。
- 默认的事件都是冒泡模式下触发的。
二维转一维数组,扁平化
1、flat
flat是ES10新增的一个数组处理的方法,非常的好用,它专门用来扁平化数组。
合并返回新数组
参数是层级数,默认为1,层级未知可以用Infinity
2、concat + 扩展符
concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
扩展运算符(...)可以将数组转为用逗号分隔的参数序列。
只能二维转一维,多维就不行
3、reduce + concat
reduce() 方法接收一个函数作为累加器,reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(上一次回调的返回值),当前元素值,当前索引,原数组 。
callback:函数中包含四个参数
- previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
- currentValue (数组中当前被处理的元素)
- index (当前元素在数组中的索引)
- array (调用的数组)
initialValue (作为第一次调用 callback 的第一个参数。)
将初始值设置为了[]空数组,然后将需要扁平化的数组的每一项都用concat重新连接,最终得到一个一维数组。
4、toString + split
先使用 toString 把数组转成字符串,再使用 split 把字符串转回数组:
该方法存在局限性,不适用于一些包含相对特殊子元素的数组,比如包含 null、undefined、对象类型等。
使用map是为了让数组元素变为Number类型。
单点登录
概念: 一个大型公司有很多系统,用的是同一个账号,登录一个系统时,其它系统也可以正常访问
cookie:
某个系统登陆成功,再次去登录其它系统系带token,token如何在多个网站中共享
domain/path
domain: 设置网站域名 设置为主域名(父级域名)/二级域名是可以获取到cookie数据
path: 路径 /
脱离父级域名不可以共享了
认证中心
iframe