面试经验分享

Caleb ... 2021-04-06
  • 面经
大约 9 分钟

注意

金三银四,又到了每年换工作的黄金时间,正好最近也准备找新工作,顺便将面试过程中的一些题目进行总结。

# JS 相关问题

# 1.js 中事件执行顺序?

提示

先进行事件捕获过程、然后调用目标元素事件,最后执行事件冒泡。

# 2.事件捕获和事件冒泡之间的区别。

提示

在操作一堆嵌套的元素时,如果目标元素嵌套在第四层,那么当点击目标元素时会从第一层捕获到第四层目标元素上,然后此时执行目标元素绑定的事件,结束后从目标元素开始又一层一层向上冒泡。

通过 obj.addEventListener(event,function(){},bool) 的 bool 属性来确定捕获阶段和冒泡阶段,bool 为 true 时,当前函数捕获阶段触发。反之为冒泡阶段触发。

阻止冒泡 w3c 的方法是 e.stopPropagation(),IE 则是使用 e.cancelBubble = true;

额外知识点: 如果在捕获阶段阻止了事件,那么此流程就会被阻止掉,不会触发后续的操作。

# 3.什么是闭包? 你有没有在实际开发中使用过?

提示

闭包就是能够读取其他函数内部变量的函数。由于在 Javascript 语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

使用闭包的注意点:

  1. 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在 IE 中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

  2. 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

警告

开发中使用的地方,比如我定义了一个函数,这个函数会帮我在页面生成一些 dom,如果不做限制的话,每次 new 函数就会生成一次,如果恶意操作会造成页面卡顿等。

let ProxySingletonDialog = (function() {
  let instance, initFlag;
  return function(option) {
    if (!instance) {
      initFlag = false;
      instance = new Dialog({ ...option, initFlag });
    }
    return instance;
  };
})();

window.Dialog = ProxySingletonDialog;
1
2
3
4
5
6
7
8
9
10
11
12

# 4.节流防抖函数。

提示

函数节流:是确保函数特定的时间内至多执行一次。 函数防抖:是函数在特定的时间内不被再调用后执行。

节流函数

let canRun = false;
function throttle() {
  if (!canRun) {
    canRun = true;
    setTimeout(() => {
      canRun = false;
      console.log("节流函数");
    }, 1000);
  }
}
window.addEventListener("resize", throttle, false);
1
2
3
4
5
6
7
8
9
10
11

防抖函数

function debounce(fn, delay) {
  let timer = null;
  return (...arg) => {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arg);
    }, delay);
  };
}
function click() {
  console.log("防抖函数");
}
document.addEventListener("click", debounce(click, 200), false);
1
2
3
4
5
6
7
8
9
10
11
12
13

# vue 相关问题

# 1.vue 生命周期是什么?

提示

vue2.x 生命周期:

beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
beforeDestroy
destroyed

vue3 生命周期

setup --> 代替了 vue2 中的 create 阶段函数 onBeforeMount
onMounted
onBeforeUpdate
onUpdated
onBeforeUnmount
onUnmounted

# 2.vue 中的$nextTick()是什么?

提示

Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。
$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM

# 3.axios 有没有二次封装? 封装了哪些功能?

提示

有过封装,比如在请求拦截器中,给header中添加 Token,或者通过参数修改请求头格式等。

加载全局请求 Loading 状态。在请求开始前打开,结束后关闭。

在返回拦截器中对返回 code 状态进行判断,无权则跳转无权界面,错误则跳转错误界面,随后将正确请求内容 return 出去。

# 4.如何处理用户登录逻辑以及获取用户信息的功能?

提示

可以在 vuex 中定义好用户的基本信息,然后在用户登录时将后端返回的信息更新到 vuex 中,并将返回的 Token 信息存放在 cookies 中。登录成功后使用 router 的 push 方法跳转路由到 home 页面。

因为 vuex 里的内容在刷新后就不存在了,所以我使用如下方法:

在路由守卫的钩子函数中查找 vuex 中的某一项用户信息是否存在,如果存在则进行其他的操作,例如权限判断。反之不存在的话,就需要通过另外一个获取用户信息的接口来拿到用户信息,并更新 vuex 中相对应的属性。

通过这一接口在每次刷新页面后就可快速拿到用户数据。

# 5.你们的项目中是怎么处理权限问题的?

提示

1.前端效验法

在定义路由初期时就定义好一个自定义属性,例如 access 属性,标志好权限内容,将权限内容发给后端,后端给对应的用户添加上当前权限内容。

在路由守卫的钩子函数中,每次路由的跳转都进行权限的效验,如果当前用户登录后的用户信息中并没有当前路由的权限,就跳转无权页面。反之则通过,使用next()方法进行路由处理。

至于侧边菜单栏的生成,需要在项目运行初期先进行权限比对,生成有权路由信息,交给封装好的侧边栏组件进行渲染。

2.后端返回法

在项目开始初期就先进行路由信息输入页面的处理,将新页面的信息录入到后端,并在权限分配页面进行用户权限的分配。

用户登录后,在路由守卫的钩子函数中,将后端返回的路由表信息进行逻辑处理,将杂乱的信息转化为 vue-router 可识别的对象数据。通过addRoute()方法将生成的路由表 push 进 router 对象中。

侧边栏就可以直接使用生成的内容进行渲染

# 6.有没有使用过混入方法?

提示

使用过,混入方法主要用来提取一些页面公共方法,减少代码的冗余。常见业务就是比如在表格中会有排序方法,然后分页中也会有一些关于分页内容的方法,这些方法函数都是一致的,所以可以抽离出来,使得其他页面可以共用。

# 7.组件传值有哪些?

提示

常见的三个方法在这里 组件传值

补充方法:vuex provide/inject

# 8.自己封装过组件吗? 如果两个组件中有 80%的共用部分请问如何抽离?

提示

使用<slot></slot>插槽。抽离共用的部分,然后将需要自定义的地方使用slot引入。

包括匿名插槽、具名插槽等

slot插槽使用方法 (opens new window)

# 9.在提交一次表单后,如何快捷的将表单绑定的对象进行重置?

提示

使用 this.$options().data.xxxx xxxx 代指的就是需要重置的对象。

# 10.在使用一些第三方 UI 组件时,如果更新他们的默认样式?

提示

1.可以在调用初期使用 UI 组件提供的初始化方法将组件重构成自己需要的样式,比如修改整体颜色之类的。

2.在 vue 文件中,可以通过使用样式穿透方法进行样式调整。.父元素class /deep/ .需要调整元素class

# 11.vue 双向绑定原理?

提示

在 new Vue() 后传入了基本数据,Vue 会先把 data 的内容通过Object.defineProperty()劫持。然后调用Observer类将劫持后数据内部的属性再劫持处理一次。 在这个过程中,会在数据处理的 get 方法中将观察者Dep类注入,并会在 set 方法中通知所有的订阅者更新视图。在Compiler类中将页面中的特殊指令和模板解析,然后调用 data 中的对应属性进行替换,并在相应的处理函数中将订阅者绑定。订阅者Watcher类会先把自身存放进观察者属性中,绑定后订阅者会先触发一次 get 方法,将自己添加进观察者的通知队列中。然后双向绑定的地方需要使用 dom 的属性方法比如 input 的 input 方法将数据改动后告诉 set 方法,那么观察者就会通知队列进行更新。

# CSS 相关问题

# 1.css 中怎样实现垂直居中布局?

提示

1.弹性盒子布局。 2.子绝父相。 3.网格布局。

问题分析。主要就是考一下基础的 css 属性组合,酌情回答两到三种就可以了。垂直居中布局详解 (opens new window)

# 2.css 中弹性盒子使用过没有?使用了什么属性?

提示

具体可查看之前分享的弹性盒子内容,不做赘述。

# 3.css 一个 div 元素如何实现汉堡包菜单图标?

如左图所示

<div class="box"></div>
<style>
  .box {
    position: relative;
    width: 20px;
    height: 3px;
    top: 6px;
    background: #333;
  }
  .box::before,
  .box::after {
    position: absolute;
    content: " ";
    width: 20px;
    height: 3px;
    background: #333;
  }
  .box::before {
    top: -6px;
  }
  .box::after {
    top: 6px;
  }
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 其他问题

# 1.假设页面中的侧边栏菜单有 5000 条,需要如何处理才能更好的平衡性能和用户体感?

提示

1.分步渲染,先对侧边栏的数据进行处理,比如先展示 20 条,通过数组的切割方法,将数据剥离渲染。

2.滚动监听,监听侧边栏滚动,如果滚动到底部,展示 loading 状态。并再次切割数据,更新渲染。关闭 loading 展示。

# 2.ifream 父子页面之间如何通信?

打赏