1.JS中的函数上下文
在JS中,函数的上下文是可以变化的,函数内的this也是可以变化的,函数可以作为一个对象的方法,也可以同时作为另一个对象的方法,因此可以通过修改函数上下文来改变函数指向。通过使用call、apply、bind方法来修改this的指向。
function updown( fn,obj){
return fn.apply(obj); // return fn.call(obj); // return fn.bind(obj);
}
2.闭包
函数闭包是指内部变量可以在外部访问,即函数外部可以访问到内部声明函数变量。闭包打破了变量的作用域规则,变量不会被垃圾回收,但是使用闭包会导致内存泄漏。
3.Vue的生命周期
Vue的声明周期分为初始化、运行中、销毁三部分。开始创建——初始化数据——编译模板——解析为AST——编译为render函数——挂载DOM——渲染——更新——渲染——销毁一系列过程称之为Vue的生命周期。
主要的钩子函数包括创建前;创建(created);挂载前;挂载(mounted);更新前;更新(updated);销毁前;销毁(destoryed)。
创建前完成初始化操作,但此时数据还未进行绑定;创建则完成了数据的绑定配置,计算属性及方法的挂载,event事件的回调。
挂载前完成页面模板的解析,生成抽象语法树(AST),并将解析后的页面模板存储在内存中;挂载则是将内存中的内容渲染到页面上,实现虚拟DOM树操作,及AST通过编译为render函数将其翻译为虚拟DOM树,渲染在UI页面上。
更新前是指数据发生更新时,钩子函数将会被调用,但此时页面中的数据依旧为原来数据,而Vue中的数据已经是最新的,可以进一步更改其状态。更新是发生在数据要更新并在DOM树中渲染后调用的钩子函数。
销毁前是指实例被销毁之前调用的钩子函数,但此时实例仍然可用;销毁是在实例被销毁之后调用,此时与Vue帮定的所有都回解绑,监听器移出,子例被销毁。
4.Vue响应式原理
所谓响应式就是在页面控制台,改变绑定数据属性值,页面上的内容将随之改变。通过object.defineProperty对数据的属性进行添加或修改。数据绑定是一个一步操作,首先observer监听对象上的所有属性,在属性值改变时触发watcher,然后由其执行回调函数,更新Vue模板上的内容。其中每一个observer对应一个Dep数组,用来保存与observer相关的watcher。
在Vue3中使用proxy代替object.defineProperty实现数据的双向绑定,因为proxy可以监听整个对象。
5.diff算法
虚拟DOM树中的采用的算法,将树进行层级分解,只比较相同层级节点进行创建和删除操作。在Vue2中,使用深度遍历算法对新旧DOM树进行对比,以便进行页面更新。而在Vue3中将编译器与运行同时进行工作,不在递归遍历DOM树,而是找到动态改变节点结构的模板指令对其进行执行树遍历,以减少虚拟DOM的大部分开销。
6.防抖与节流
Vue中没有内置防抖与节流,需要使用Lodash库实现,每个组件只使用一次,在methods中直接应用防抖。
<script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
<script>
Vue.createApp({
methods: {
// 用 Lodash 的防抖函数
click: _.debounce(function() {
// ... 响应点击 ...
}, 500)
}
}).mount('#app')
</script>
7.Vue导航守卫
导航守卫主要是通过跳转或取消的方式守卫导航,简而言之就是路由跳转过程中的一些钩子函数。导航守卫分为:全局守卫、路由独享守卫、组件内守卫。导航守卫有三个参数:to, from,next.。next为进入下一个管道的钩子。
(1)全局守卫分为:全局前置守卫,全局解析守卫,全局后置钩子
全局前置守卫:在路由刚开始导航且还未进入路由对应的组件中触发。
const router = new VueRouter({ /*...*/ })
router.beforeEach((to, from, next) => {
// ... // if (...) next(); else next("/login");
})
全局解析守卫:在导航被确认之前,同时所有的组件守卫和异步路由组件被解析之后,解析守卫才被调用。
const router = new VueRouter({ /*...*/ })
router.beforeResolve((to, from, next) => {
// ...
})
全局后置钩子:不会接受next函数也不会改变导航本身。
const router = new VueRouter({ /*...*/ })
router.afterEach((to, from) => {
// ...
})
(2)路由独享守卫:是当组件路由进入时触发的。
const router = new VueRouter({
routes: [{
path: "/example",
component: Example,
beforeEnter: (to, from, next) => {
// ...
}
}]
})
(3)组件内守卫分为:组件前置守卫,组件更新守卫,组件离开守卫
组件前置守卫:在还没有进入该组件之前触发,渲染该组件的对应路由被confirm前调用。
const Example = {
template: `...`,
beforeRouteEnter: function(to, from, next) {
// ...
}
}
组件更新守卫:动态路由中,切换路由时由于绑定的是同一个组件因此不会重新渲染,在钩子函数中获异步动态路由对应数据,访问实例。
const Example = {
template: `...`,
beforeRouteUpdate: function(to, from, next) {
// ...
}
}
组件离开守卫:导航离开该组件的对应路由时调用,访问组件实例this,
const Example = {
template: `...`,
beforeRouteLeave: function(to, from, next) {
// ...
}
}
8.父子组件之间的通信方式
(1)父组件与子组件进行通信是通过v-bind的props属性绑定。
(2)子组件与父组件之间通信则通过绑定事件$event事件
9.前端跨域问题如何解决
跨域解决的是同源问题。同源主要是”协议+域名+端口“只要有一者不同则为不同源。同源策略限制以下行为:
cookie、LocalStorage和IndexDB无法获取
DOM和JS对象无法获得
Ajax请求不能发送。
(1)JSONP解决跨域问题,只支持get请求,适合加载不同域名的js、CSS、img等静态资源。
(2)CORS解决跨域问题,跨域资源共享,适用于Ajax各种跨域请求;
(3)Nignx代理nodejs中间插件跨域原理为搭建一个服务器,直接在服务器上请求http接口,适合前后端分离项目中前端调用后端接口。
(4)document.domain+iframe适合主域相同,子域不同跨域请求。
(5)postMessage是HTML5中XMLHttpRequest Level2中的API,解决页面与新打开窗口之间数据传递,多窗口之间消息传递,页面与嵌套iframe消息传递。
(6)websocket协议为HTML5的新特性,支持服务器与浏览器双向数据传递,使用socketio,很好的封装了websocket接口,支持浏览器向下兼容。
参考地址:https://www.imooc.com/article/291931
10.HTTP状态码
(1)1开头:被接受,需要继续处理
(2)2开头:请求成功
(3)3开头:请求被重定向
301重新请求的URL,客户端自动重新请求新的地址;
(4)4开头:请求错误,客户端看起来可能发生了错误,妨碍了服务器处理。
400:错误请求,请求语法不同或不能满足请求;403禁止,即使授权也不需要访问;404找不到给定资源,文档不存在;405:打开方式不对,资源被禁止。
(5)5开头:服务器错误