2024年Web前端最全「自我检验」熬夜总结50个Vue知识点,全都会你就是神!!(2),面试题难忘的个人经历

数据结构与算法

这一块在笔试、面试的代码题中考核较多,其中常考的数据结构主要有:数组、链表、队列、栈、Set、Map、哈希表等,不同数据结构有不同的方法以及储存原理,这些算是技术岗的必备知识。算法部分主要分为两大块,排序算法与一些其他算法题

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

排序算法根据考频高低主要有:快速排序、归并排序、堆排序、冒泡排序、插入排序、选择排序、希尔排序、桶排序、基数排序、Timsort这十种,这类考核点要么是算法的时间、空间复杂度、稳定度,要么是直接手写代码,故在理解算法原理的同时,对JS语言版的排序算法代码也要加强记忆。

  • 二叉树层序遍历
  • B 树的特性,B 树和 B+树的区别
  • 尾递归
  • 如何写一个大数阶乘?递归的方法会出现什么问题?
  • 把多维数组变成一维数组的方法
  • 知道的排序算法 说一下冒泡快排的原理
  • Heap 排序方法的原理?复杂度?
  • 几种常见的排序算法,手写
  • 数组的去重,尽可能写出多个方法
  • 如果有一个大的数组,都是整型,怎么找出最大的前 10 个数
  • 知道数据结构里面的常见的数据结构
  • 找出数组中第 k 大的数组出现多少次,比如数组【1,2, 4,4,3,5】第二大的数字是 4,出现两次,所以返回 2
  • 合并两个有序数组
  • 给一个数,去一个已经排好序的数组中寻找这个数的位 置(通过快速查找,二分查找)

小林
小明
  
小明
小红
  
小红
小花
  
小花

可以看出,原有的三项都不变,只是新增了小林这个人,这才是最理想的结果

index和用随机数都是同理,随机数每次都在变,做不到专一性,很渣男,也很消耗性能,所以,拒绝渣男,选择老实人

26. 说说nextTick的用处?

我举个例子,在vue中:

this.name = ‘林三心’

this.age = 18

this.gender = ‘男’

我们修改了三个变量,那问题来了,是每修改一次,DOM就更新一次吗?不是的,Vue采用的是异步更新的策略,通俗点说就是,同一事件循环内多次修改,会统一进行一次视图更新,这样才能节省性能嘛

看懂了上面,那你应该也看得懂下面的例子了吧:

{{name}}

name: ‘小林’

this.name = ‘林三心’

console.log(this.$refs.testDiv.innerHTML) // 这里是啥呢

答案是“小林”,前面说了,Vue是异步更新,所以数据一更新,视图却还没更新,所以拿到的还是上一次的旧视图数据,那么想要拿到最新视图数据怎么办呢?

this.name = ‘林三心’

this.$nextTick(() => {

console.log(this.$refs.testDiv.innerHTML) // 林三心

})

27. Vue的SSR是什么?有什么好处?

  • SSR就是服务端渲染

  • 基于nodejs serve服务环境开发,所有html代码在服务端渲染

  • 数据返回给前端,然后前端进行“激活”,即可成为浏览器识别的html代码

  • SSR首次加载更快,有更好的用户体验,有更好的seo优化,因为爬虫能看到整个页面的内容,如果是vue项目,由于数据还要经过解析,这就造成爬虫并不会等待你的数据加载完成,所以其实Vue项目的seo体验并不是很好

最强王者


28. Vue响应式是怎么实现的?

整体思路是数据劫持+观察者模式

对象内部通过 defineReactive 方法,使用 Object.defineProperty 将属性进行劫持(只会劫持已经存在的属性),数组则是通过重写数组方法来实现。当页面使用对应属性时,每个属性都拥有自己的dep属性,存放他所依赖的 watcher(依赖收集),当属性变化后会通知自己对应的 watcher 去更新(派发更新)。

想详细了解过程,建议阅读我的Vue源码解析系列[5]

const { arrayMethods } = require(‘./array’)

class Observer {

constructor(value) {

Object.defineProperty(value, ‘ob’, {

value: this,

enumerable: false,

writable: true,

configurable: true

})

if(Array.isArray(value)) {

value.proto = arrayMethods

this.observeArray(value)

} else {

this.walk(value)

}

}

walk(data) {

let keys = Object.keys(data)

for(let i = 0; i < keys.length; i++) {

const key = keys[i]

const value = data[key]

defineReactive(data, key, value)

}

}

observeArray(items) {

for(let i = 0; i < items.length; i++) {

observe(items[i])

}

}

}

function defineReactive(data, key, value) {

const childOb = observe(value)

const dep = new Dep()

Object.defineProperty(data, key, {

get() {

console.log(‘获取值’)

if (Dep.target) {

dep.depend()

if (childOb) {

childOb.dep.depend()

if (Array.isArray(value)) {

dependArray(value)

}

}

}

return value

},

set(newVal) {

if (newVal === value) return

observe(newVal)

value = newVal

dep.notify()

}

})

}

function observe(value) {

if (Object.prototype.toString.call(value) === ‘[object Object]’ || Array.isArray(value)) {

return new Observer(value)

}

}

function dependArray(value) {

for(let e, i = 0, l = value.length; i < l; i++) {

e = value[i]

e && e.ob && e.ob.dep.depend()

if (Array.isArray(e)) {

dependArray(e)

}

}

}

// array.js

const arrayProto = Array.prototype

const arrayMethods = Object.create(arrayProto)

const methodsToPatch = [

‘push’,

‘pop’,

‘shift’,

‘unshift’,

‘splice’,

‘reverse’,

‘sort’

]

methodsToPatch.forEach(method => {

arrayMethods[method] = function (…args) {

const result = arrayProto[method].apply(this, args)

const ob = this.ob

var inserted

switch (method) {

case ‘push’:

case ‘unshift’:

inserted = args

break;

case ‘splice’:

inserted = args.slice(2)

default:

break;

}

if (inserted) ob.observeArray(inserted)

ob.dep.notify()

return result

}

})

29. 为什么只对对象劫持,而要对数组进行方法重写?

因为对象最多也就几十个属性,拦截起来数量不多,但是数组可能会有几百几千项,拦截起来非常耗性能,所以直接重写数组原型上的方法,是比较节省性能的方案

30. Vue的模板编译原理?

因为这个问题讲起来可能比较长,所以:

建议看我这篇「Vue源码学习\(二\)」你不知道的-模板编译原理[6]

31. Vue的computed和watch的原理?

因为这个问题讲起来可能比较长,所以:

建议看我这篇「Vue源码学习\(四\)」立志写一篇人人都看的懂的computed,watch原理[7]

32. Vue.set方法的原理?

function set(target, key, val) {

// 判断是否是数组

if (Array.isArray(target)) {

// 判断谁大谁小

target.length = Math.max(target.length, key)

// 执行splice

target.splice(key, 1, val)

return val

}

const ob = target.ob

// 如果此对象没有不是响应式对象,直接设置并返回

if (key in target && !(key in target.prototype) || !ob) {

target[key] = val

return val

}

// 否则,新增属性,并响应式处理

defineReactive(target, key, val)

return val

}

33. Vue.delete方法的原理?

function del (target, key) {

// 判断是否为数组

if (Array.isArray(target)) {

// 执行splice

target.splice(key, 1)

return

}

const ob = target.ob

// 对象本身就没有这个属性,直接返回

if (!(key in target)) return

// 否则,删除这个属性

delete target[key]

// 判断是否是响应式对象,不是的话,直接返回

if (!ob) return

// 是的话,删除后要通知视图更新

ob.dep.notify()

}

34. nextTick的原理?

let callbacks = []; //回调函数

let pending = false;

function flushCallbacks() {

pending = false; //把标志还原为false

// 依次执行回调

for (let i = 0; i < callbacks.length; i++) {

callbacksi;

}

}

let timerFunc; //先采用微任务并按照优先级优雅降级的方式实现异步刷新

if (typeof Promise !== “undefined”) {

// 如果支持promise

const p = Promise.resolve();

timerFunc = () => {

p.then(flushCallbacks);

};

} else if (typeof MutationObserver !== “undefined”) {

// MutationObserver 主要是监听dom变化 也是一个异步方法

let counter = 1;

const observer = new MutationObserver(flushCallbacks);

const textNode = document.createTextNode(String(counter));

observer.observe(textNode, {

characterData: true,

});

timerFunc = () => {

counter = (counter + 1) % 2;

textNode.data = String(counter);

};

} else if (typeof setImmediate !== “undefined”) {

// 如果前面都不支持 判断setImmediate

timerFunc = () => {

setImmediate(flushCallbacks);

};

} else {

// 最后降级采用setTimeout

timerFunc = () => {

setTimeout(flushCallbacks, 0);

};

}

export function nextTick(cb) {

callbacks.push(cb);

if (!pending) {

pending = true;

timerFunc();

}

}

35. key有什么用?说说diff算法吧?

直接看这篇吧:为什么 Vue 中不要用 index 作为 key?(diff 算法详解)[8]

我讲的没他好

冷门的知识点


36. 如果子组件改变props里的数据会发生什么

  • 改变的props数据是基本类型

如果修改的是基本类型,则会报错

props: {

num: Number,

}

created() {

this.num = 999

}

0458e2ff1538ee85d42953cec9a94ca.png

  • 改变的props数据是引用类型

props: {

item: {

default: () => {},

}

}

created() {

// 不报错,并且父级数据会跟着变

this.item.name = ‘sanxin’;

// 会报错,跟基础类型报错一样

this.item = ‘sss’

},

37. props怎么自定义验证

props: {

num: {

default: 1,

validator: function (value) {

// 返回值为true则验证不通过,报错

return [

1, 2, 3, 4, 5

].indexOf(value) !== -1

}

}

}

38. watch的immediate属性有什么用?

比如平时created时要请求一次数据,并且当搜索值改变,也要请求数据,我们会这么写:

created(){

this.getList()

},

watch: {

searchInputValue(){

this.getList()

}

}

复制代码

使用immediate完全可以这么写,当它为true时,会初始执行一次

watch: {

searchInputValue:{

handler: ‘getList’,

immediate: true

}

}

39. watch监听一个对象时,如何排除某些属性的监听

下面代码是,params发生改变就重新请求数据,无论是a,b,c,d属性改变

data() {

return {

params: {

a: 1,

b: 2,

c: 3,

d: 4

},

};

},

watch: {

params: {

deep: true,

handler() {

this.getList;

},

},

}

但是如果我只想要a,b改变时重新请求,c,d改变时不重新请求呢?

mounted() {

Object.keys(this.params)

.filter(() => ![“c”, “d”].includes()) // 排除对c,d属性的监听

.forEach((_) => {

this.$watch((vm) => vm.params[_], handler, {

deep: true,

});

});

},

data() {

return {

params: {

a: 1,

b: 2,

c: 3,

d: 4

},

};

},

watch: {

params: {

deep: true,

handler() {

this.getList;

},

},

}

40. 审查元素时发现data-v-xxxxx,这是啥?

image.png

这是在标记vue文件中css时使用scoped标记产生的,因为要保证各文件中的css不相互影响,给每个component都做了唯一的标记,所以每引入一个component就会出现一个新的’data-v-xxx’标记

41. computed如何实现传参?

// html

{{ total(3) }}

// js

computed: {

total() {

return function(n) {

return n * this.num

}

},

}

42. vue的hook的使用

  • 同一组件中使用

这是我们常用的使用定时器的方式

export default{

data(){

timer:null

},

mounted(){

this.timer = setInterval(()=>{

//具体执行内容

console.log(‘1’);

},1000);

}

beforeDestory(){

clearInterval(this.timer);

this.timer = null;

}

}

上面做法不好的地方在于:得全局多定义一个timer变量,可以使用hook这么做:

export default{

methods:{

fn(){

const timer = setInterval(()=>{

//具体执行代码

console.log(‘1’);

},1000);

this.$once(‘hook:beforeDestroy’,()=>{

clearInterval(timer);

timer = null;

})

}

}

}

  • 7.2 父子组件使用

如果子组件需要在mounted时触发父组件的某一个函数,平时都会这么写:

//父组件

<rl-child @childMounted=“childMountedHandle”

/>

method () {

childMountedHandle() {

// do something…

}

},

// 子组件

mounted () {

this.$emit(‘childMounted’)

},

使用hook的话可以更方便:

//父组件

<rl-child @hook:mounted=“childMountedHandle”

/>

method () {

childMountedHandle() {

// do something…

}

},

43. provide和inject是响应式的吗?

// 祖先组件

provide(){

return {

// keyName: { name: this.name }, // value 是对象才能实现响应式,也就是引用类型

keyName: this.changeValue // 通过函数的方式也可以[注意,这里是把函数作为value,而不是this.changeValue()]

// keyName: ‘test’ value 如果是基本类型,就无法实现响应式

}

},

data(){

return {

name:‘张三’

}

},

methods: {

changeValue(){

this.name = ‘改变后的名字-李四’

}

}

// 后代组件

inject:[‘keyName’]

create(){

console.log(this.keyName) // 改变后的名字-李四

}

44.Vue的el属性和$mount优先级?

比如下面这种情况,Vue会渲染到哪个节点上

new Vue({

router,

store,

el: ‘#app’,

render: h => h(App)

}).$mount(‘#ggg’)

这是官方的一张图,可以看出el$mount同时存在时,el优先级 > $mount

image.png

45. 动态指令和参数使用过吗?

<aButton @[someEvent]=“handleSomeEvent()” :[someProps]=“1000” />…

46. 相同的路由组件如何重新渲染?

开发人员经常遇到的情况是,多个路由解析为同一个Vue组件。问题是,Vue出于性能原因,默认情况下共享组件将不会重新渲染,如果你尝试在使用相同组件的路由之间进行切换,则不会发生任何变化。

const routes = [

{

path: “/a”,

component: MyComponent

},

{

path: “/b”,

component: MyComponent

},

];

如果依然想重新渲染,怎么办呢?可以使用key

47. 自定义v-model

默认情况下,v-model 是 @input 事件侦听器和 :value 属性上的语法糖。但是,你可以在你的Vue组件中指定一个模型属性来定义使用什么事件和value属性——非常棒!

export default: {

model: {

event: ‘change’,

prop: ‘checked’

}

最后

喜欢的话别忘了关注、点赞哦~

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

前端校招面试题精编解析大全

这是官方的一张图,可以看出el$mount同时存在时,el优先级 > $mount

image.png

45. 动态指令和参数使用过吗?

<aButton @[someEvent]=“handleSomeEvent()” :[someProps]=“1000” />…

46. 相同的路由组件如何重新渲染?

开发人员经常遇到的情况是,多个路由解析为同一个Vue组件。问题是,Vue出于性能原因,默认情况下共享组件将不会重新渲染,如果你尝试在使用相同组件的路由之间进行切换,则不会发生任何变化。

const routes = [

{

path: “/a”,

component: MyComponent

},

{

path: “/b”,

component: MyComponent

},

];

如果依然想重新渲染,怎么办呢?可以使用key

47. 自定义v-model

默认情况下,v-model 是 @input 事件侦听器和 :value 属性上的语法糖。但是,你可以在你的Vue组件中指定一个模型属性来定义使用什么事件和value属性——非常棒!

export default: {

model: {

event: ‘change’,

prop: ‘checked’

}

最后

喜欢的话别忘了关注、点赞哦~

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

前端校招面试题精编解析大全

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值