web高级前端面试实战总结

目录

Vue相关

JS相关问题



Vue相关

1.vue的路由有哪些模式?分别有什么异同(优缺点)

答:首先路由有三种模式;hash模式、history模式、abstract模式

       hash模式:使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载,其显示的网路路径中会有 “#” 号,有一点点丑。这是最安全的模式,因为他兼容所有的浏览器和服务器。

                          缺点:只能改变#后面的来实现路由跳转。

       history模式:美化后的hash模式,会去掉路径中的 “#”。依赖于Html5 的history,pushState API,所以要担心IE9以及一下的版本;包括back、forward、go三个方法,对应浏览器的前进,后退,跳转操作。就是浏览器左上角的前进、后退等按钮进行的操作。

                          history.go(-2);//后退两次
                          history.go(2);//前进两次
                          history.back(); //后退
                          hsitory.forward(); //前进

                          缺点:如果后端没有设置对应路由,直接访问会出现404;怕刷新

      abstract模式:适用于所有JavaScript环境,例如服务器端使用Node.js。如果没有浏览器API,路由器将自动被强制进入此模式。

2.vue中的route和router的区别;

答:route是路由信息对象,里面有name,path,params,query等信息参数

       router是一个VueRouter的实例对象,里面含有很多属性和子对象(history),push方法等【直接通过path手写this.$router.push({path:`/user/${userId}`});也可以用params传递(通过name);也可以用query传递(通过path)】

3.vue-router的原理

更新视图但不重新请求页面,是前端路由原理的核心之一

(1)利用URL中的hash("#");  hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页;

(2)利用History interface在HTML5中新增的方法;利用 history.pushState API 来完成 URL 跳转而无须重新加载页面

4.vue.nextTick()方法,和实现原理

定义:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

理解:nextTick(),是将回调函数延迟在下一次dom更新数据后调用,简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数,

何时使用?

(1)Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中

(2)当项目中你想在改变DOM元素的数据后基于新的dom做点什么,对新DOM一系列的js操作

(3)在使用某个第三方插件时 ,希望在vue生成的某些dom动态发生变化时重新应用该插件

使用原理

Vue DOM更新是异步执行的,即修改数据时,视图不会立即更新,所以需要在dom更新后再去执行nextTick(),一个事件循环为一个tick,要想在更新dom后操作js,就需要在下一个tick中执行,所以需要使用nextTick();

5.computed 和 watch 的区别和运用的场景

computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;(需要进行数值计算,并且依赖于其它数据时使用)
watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;(可以执行异步,调用api,在得到借过前设置中间状态等)

  1. computed 是计算一个新的属性,并将该属性挂载到 vm(Vue 实例)上,而 watch 是监听已经存在且已挂载到 vm 上的数据,所以用 watch 同样可以监听 computed 计算属性的变化(其它还有 dataprops
  2. computed 本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问 computed 属性,才会计算新的值,而 watch则是当数据发生变化便会调用执行函数
  3. 从使用场景上说,computed 适用一个数据被多个数据影响,而 watch 适用一个数据影响多个数据;

 watch中有哪些参数和方法

immediate:(立即执行)在初始化的时候watch是不会执行的,如果想要执行,设置immediate为true

deep:(深度监听)监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,此时就需要deep属性对对象进行深度监听。设置deep为true

handler:deep会给所有的属性都加上handler;如果只需要监听对象中的一个属性值,则可使用handler(new,old):使用字符串的形式监听对象属性:


data() {
    return {
        list: {
            'id': 1,
            'type': 0
        }
    }
},
watch: {
    'list.id': {
        handler(newVal, oldVal) {
             ......
        },
    deep: true
    }    
}
原文链接:https://blog.csdn.net/HelloMy_sun/article/details/106214277

6.Vue 响应系统

  1. observe:遍历 data 中的属性,使用 Object.defineProperty 的 get/set 方法对其进行数据劫持;
  2. dep:每个属性拥有自己的消息订阅器 dep,用于存放所有订阅了该属性的观察者对象;
  3. watcher:观察者(对象),通过 dep 实现对响应属性的监听,监听到结果后,主动触发自己的回调进行响应。

7.v-model指令的实现原理 - 如何利用v-model设计自定义的表单组件

v-model是一个语法糖,本质还是v-bind绑定了表单的input方法

官方文档:

8.keep-alive原理及实现

简单介绍:是一个vue的内置组件,提供了include与exclude属性,允许组件有条件地进行缓存,其中exclude的优先级比include高,max最多可以缓存多少组件实例;

钩子函数:对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。

原理:在created钩子会创建一个cache对象,用来作为缓存容器,保存vnode节点。在需要重新渲染的时候再将vnode节点从cache对象中取出并渲染。在destroyed钩子则在组件被销毁的时候清除cache缓存中的所有组件实例。

源码:

export default {
  props: {
    include: patternTypes, // 允许组件有条件地进行缓存
    exclude: patternTypes,
    max: [String, Number] // 最多可以缓存多少组件实例
  },
  created () {
    this.cache = Object.create(null) // 创建一个cache对象,用来作为缓存容器,保存vnode节点
    this.keys = []
  },
  destroyed () {
    // 清除cache缓存中的所有组件实例
    for (const key in this.cache) {
      pruneCacheEntry(this.cache, key, this.keys)
    }
  },
}
function pruneCacheEntry (
  cache: VNodeCache,
  key: string,
  keys: Array<string>,
  current?: VNode
) {
  const cached = cache[key]
  if (cached && (!current || cached.tag !== current.tag)) {
    cached.componentInstance.$destroy()
  }
  cache[key] = null
  remove(keys, key)
}

怎么手动清除组件缓存?

可以在配置<keep-alive>标签的:include的时候用一个动态数组,然后在路由钩子(beforeRouteLeave(to, from, next))中清除动态数组中对应的不需要的缓存组件名

9.为什么Vue组件中的data是一个函数

因为如果是对象的话,属性都回被挂到vue实例上,会使得vue很重,组件之间的数据也会被污染,会使得组件变得耦合

10.不同版本vue-cli区别

大区别在于vue-cli2.0和vue-cli3.0/4.0

(1).安装和创建项目还有启动的命令不同;

(2).创建的目录结构不同

vue-cli3/cli4中移除了配置文件目录:config 和 build 文件夹。

同时移除了 static 静态文件夹,新增了 public 文件夹,将 index.html 移动到 public 中。

(3).环境变量名有所不同

11.vuex相关

  • 1.state – 存放状态   使用this.$store.state.属性   

  • 2.getters – state的计算属性   使用$sotre.getters.fun()

  • 3.mutations – 更改状态的逻辑,同步操作   使用$store.commit('方法名',params)入参可以使单个数据,也可以是对象 (如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难)

  • 4.actions – 提交mutation,异步操作  使用$store.dispath('方法名',params)入参可以使单个数据,也可以是对象

  • 5.mudules – 将store模块化

computed: {

...mapState(['increment']),

...mapGetters(['doneTodos'])

}

详细可以看原文https://blog.csdn.net/yusirxiaer/article/details/99634868

12.vue-router全局钩子函数+单个路由钩子函数+组件内钩子函数(也可以叫做路由守卫)

(1)全局钩子beforeEach参数:to/from/next和afterEach参数:to/from

(2)单个路由钩子函数beforeEnter参数:to/from/next

(3)组件内钩子函数beforeRouteEnter+beforeRouteUpdate+beforeRouteLeave参数:to/from/next

13.Webpack相关

入口(entry)
webpack打包的起点,可以有一个或多个,一般是js文件。webpack会从起点文件开始,寻找起点直接或间接依赖的其它所有的依赖,包括JS、CSS、图片资源等,作为将来打包的原始数据
输出(output)
出口一般包含两个属性:path和filename。用来告诉webpack打包的目标文件夹,以及文件的名称。目的地也可以有多个。
加载器(loader)
webpack本身只识别Js文件,如果要加载非JS文件,必须指定一些额外的加载器(loader),例如css-loader。然后将这些文件转为webpack能处理的有效模块,最后利用webpack的打包能力去处理。
插件(plugins)
插件可以扩展webpack的功能,让webpack不仅仅是完成打包,甚至各种更复杂的功能,或者是对打包功能进行优化、压缩,提高效率。

webpack的基本功能和工作原理?

  • 代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等等
  • 文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等
  • 代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载
  • 模块合并:在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件
  • 自动刷新:监听本地源代码的变化,自动构建,刷新浏览器
  • 代码校验:在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过
  • 自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。

14.前端微服务

总结:使用qiankun插件实现。在父项目配置子项目对应的路由组件,写定子项目的IP端口即可调用

原文:https://blog.csdn.net/Ag_wenbi/article/details/106915580

15.v-if和v-for有没有优先级?为什么?

v-for的优先级高于v-if;因为在源码中先判断是否是v-for后判断v-if

16.vue/前端ssr(服务端渲染)

(1)vue ssr的优势,能大大缩减网页首屏的加载时间,提升用户体验;

(2)基本的原理:在服务端生成一个html字符串,由后端将这个字符串直接发送给前端(使用vue-server-renderer)

找到一篇很详细的可以去看看,原文:https://blog.csdn.net/WU5229485/article/details/85010747?ops_request_misc=&request_id=&biz_id=102&utm_term=vue%E7%9A%84%E6%9C%8D%E5%8A%A1%E7%AB%AF&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-3-85010747.pc_search_result_no_baidu_js

16.双向绑定的原理

核心是采用数据劫持结合发布者订阅者模式,通过Object.defineProperty()对每个属性的get和set进行拦截。在数据发生变化的时候发布消息给订阅者,触发相应的监听回调。(vue3.0采用proxy实现)

Object.defineProperty()有三个参数,第一个是属性所在的对象。第二个是要操作的属性,第三个是被操作的属性的特性,是一个对象{},一般是两个get:读取属性时触发,set写入属性时触发。

三个步骤

  • 1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。

  • 2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。

  • 3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。

转载:https://blog.csdn.net/lishanleilixin/article/details/79360244

我的理解:1.通过Object.defineprototype给所有属性添加上数据劫持,通过set方法来监听数据是否变化;(在数据劫持的get方法中就已经形成了订阅者的初始化,或者说是订阅器的初始化)

                  2.所有被监听的属性都是一个watcher(订阅者),把他们全放在一个数组里dep[]这就是订阅器;(订阅者的初始化是通过属性的get方法来添加到订阅者中的)

                  3.如果数据发生变化,触发set方法里面的方法,通知所有订阅者,也就是通知订阅器;

                  4.订阅器通过循环遍历,将每一个属性都进行update(更新);

                  5.通过对dom的解析,获取所有节点的内容(文本字符串)来通过变量进行双向绑定

17.vue的渲染过程

  1. 把模板编译为render函数
  2. 实例进行挂载, 根据根节点render函数的调用,递归的生成虚拟dom(虚拟节点里面有一个属性**elm**, 这个属性指向真实的DOM节点,可以对真是的dom直接进行替换)(虚拟dom是从VNode类实例化的对象)
  3. 对比虚拟dom,渲染到真实dom
  4. 组件内部data发生变化,组件和子组件引用data作为props重新调用render函数,生成虚拟dom, 返回到步骤3

原文:https://blog.csdn.net/q3254421/article/details/89637099

18.Vue.set()

Vue.set( target, propertyName/index, value )

向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。

19.vue官方api(感觉都会问到md)

https://cn.vuejs.org/v2/api/#Vue-extend

20.父子组件传值,兄弟组件传值

(1)父传子:        父组件:<child :inputName="name">    子组件:props: ["inputName"]或props: {inputName: String,required: true}

(2)子组件向父组件传值:$emit  父组件:<child v-on:childByValue="childByValue"></child>(childByValue方法会传入子组件传过来的值)   子组件: this.$emit('childByValue', this.childValue)

(3)父组件调用子组件的方法通过ref:父组件: <children ref="c1"></children>     this.$refs.c1.childMethods();   子组件:childMethods() { alert("I am child's methods")}

(4)可以通过$parent和$children获取父子组件的参数

(5)vue 全局事件(eventBus)  :在main.js里:window.eventBus = new Vue();//注册全局事件对象  evenBus.$emit('funcName',name)触发,evenBus.$on('funcName',function(data){})监听获取

(6)vuex

(7)localstorage和sessionstorage本地缓存(sessionStorage在关闭窗口或标签页之后将会删除这些数据。)

21.如何监听数组变化?

  • 将数组的常用方法进行重写,通过包装之后的数组方法就能够去在调用的时候被监听到。
  • 通过调用 new Proxy() ,你可以创建一个代理用来替代原数组,对数组完全监控。

JS相关问题

1.原型链和继承

这个我只记了原型链继承和寄生组合继承还有es6的class xxx extends xxxparents{}

//原型链继承
function a(rucan){
  this.rucan  = rucan
}
a.prototype.func = function(rucan){
  console.log(rucan)
}

function b(){

}
b.prototype = new a()

//此时b已经继承了a的方法和属性
//call继承,寄生组合继承
function a(rucan){
  this.rucan  = rucan
}
a.prototype.func = function(rucan){
  console.log(rucan)
}

function b(){
  this.a().call(this) // 继承私有属性方法
}
b.prototype = Object.create(a.prototype)// 继承了公有方法 重定向了
b.prototype.constructor = b// 重定向后需要写这一行
//es6类继承
function a(rucan){
  this.rucan  = rucan
}
a.prototype.func = function(rucan){
  console.log(rucan)
}
class b extends a {
  
}

2.call、applay和bind

call:改变this,立即执行,入参可以是多个参数

applay:用法跟call一样,如参是数组

bind:跟call入参使用一样,只不过是延迟执行(其实就是在执行bind函数的时候不会调用函数),会返回一个新函数,调用新函数可以出发改变this指向后的结果

3.用 JavaScript 实现发布/订阅模式

简单来说就是要实现:

(1)订阅(新增一个订阅者就将其push到订阅者数组中,每个订阅者在被添加到数组的时候就给他们都添加上一个方法比如sub() )

(2)发布订阅(将订阅者数组遍历一遍,调用他们的sub() 来通知他们消息)

(3)取消订阅  (讲订阅者从订阅数组里面删除)

(4)储存订阅者(是一个数组,用来存放订阅者的)

4.压缩连续重复字符串

var str = "xxxyyyzzcc";
var a1 = []; //定义空数组存放字符
var a2 = []; //定义空数组存放字符个数

//遍历字符串
for (var i = 0; i < str.length; i++) {
	var ch = str[i]; //得到每一个字符

	//如果当前字符与数组最后一个字符相等
	if (ch == a1[a1.length - 1]) {
		a2[a2.length - 1]++;
	} else {
		a1.push(ch);
		a2[a2.length] = 1;
	}
}

// a1-->[x,y,z,c]
// a2-->[3,3,2,2]

var str2 = ""; //定义空字符串,存放新字符串
//循环拼接
for (var i = 0; i < a1.length; i++) {
	str2 = str2 + a2[i] + a1[i];
}
//去掉1
str2 = str2.split("1").join("");
document.write(str2);
————————————————
原文链接:https://blog.csdn.net/ZPD_zpd/article/details/113741512

5.闭包

闭包就是能够读取其他函数内部变量的函数。只有函数内部的子函数才能读取局部变量,在本质上,闭包是函数内部和函数外部连接起来的桥梁。

缺点:滥用闭包会造成内存泄露,因为闭包中引用到的包裹函数中定义的变量都永远不会被释放,所以我们应该在必要的时候,及时释放这个闭包函数。

原文:https://blog.csdn.net/weixin_43606158/article/details/90213668

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值