likes
comments
collection
share

八股只问vue,代码题考js🫣「Momenta一面」

作者站长头像
站长
· 阅读数 21

这是我目前见过给面试效率最高的公司,下午投的boss,没一会打电话问我五点钟能不能面试,后面选了七点钟。一面是个姐姐,声音很好听,人也很nice,辛苦她加班面我这个菜鸡了😂。下面是题目和笔者整理的答案,如有疏漏,烦请指正:

八股文

不知道宽高的块级元素如何垂直水平居中?

1.使用 flex 布局

.parent {
    display: flex;
    justify-content: center;
    align-items: center;
}

2.使用 transform 属性

.parent {
    position: relative;
}

.child {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

computed和watch的区别?

Vue中的computedwatch都是用于观察和响应Vue实例上的数据变化的。它们在使用场景和工作方式上有一些不同:

  1. computed(计算属性)

    • computed是计算属性,主要用于当一个属性依赖于一个或多个其他属性时。当依赖的数据变化时,计算属性会重新计算。
    • computed支持缓存。只有当其依赖的属性值发生变化时,计算属性才会重新计算。如果依赖的数据没有变化,那么多次访问计算属性会直接返回之前的计算结果,而不需要重新进行计算。
    • 当多个属性影响一个属性时,或者一个数据需要经过复杂的计算时,建议使用computed
  2. watch(侦听器)

    • watch主要用于观察Vue实例上某个特定数据的变化,从而执行特定的操作。
    • watch不支持缓存,数据每次变化都会执行对应的函数。
    • 当一个值发生变化后,会引起一系列操作(例如,改变其他属性值),或者在数据变化时需要执行异步或开销较大的操作时,适合使用watch

vue首屏优化?

编码阶段:

  1. 尽量减少 data 中的数据,因为 data 中的数据会增加 getter 和 setter 的数量,从而增加了对应的 watcher 的数量。
  2. 避免在同一个元素上同时使用 v-if 和 v-for,因为 v-for 的优先级比 v-if 高,同时使用它们会造成性能浪费。
  3. 如果需要给每个元素绑定事件,请使用事件代理而不是在每个元素上使用事件监听器。
  4. 对于需要频繁切换显示和隐藏的元素,请使用 v-show 替代 v-if。
  5. 使用唯一的 key 值来确保组件的唯一性。
  6. 使用路由懒加载和异步组件来减少首次加载的代码量。
  7. 使用防抖和节流来优化用户输入等频繁触发的操作。
  8. 按需导入第三方模块以减小打包体积。
  9. 对于长列表,只加载可视区域内的内容,同样的还有图片懒加载。

SEO 优化:

  1. 预渲染:通过预渲染技术生成静态 HTML 页面,以提高搜索引擎爬取效率。
  2. 服务端渲染 (SSR):将 Vue 应用程序在服务器端渲染成 HTML,并将其发送到客户端。这样可以加快首屏加载速度并提供更好的 SEO。

打包优化:

  1. 压缩代码:使用压缩工具(如 UglifyJS)来减小代码体积。
  2. Tree Shaking/Scope Hoisting:通过消除未使用的代码来减小打包体积。
  3. 使用 CDN 加载第三方模块:将第三方库放到 CDN 上以提高加载速度。
  4. 多线程打包:使用多线程构建工具(如 happypack)来加快打包速度。
  5. 抽离公共文件:将公共代码抽离成单独的文件以提高缓存效果。
  6. 优化 Source Map:在开发环境中使用合适的 Source Map 类型以提高调试效率。

用户体验:

  1. 骨架屏:在页面加载过程中显示骨架屏以提高用户体验。
  2. PWA(Progressive Web App):将 Web 应用程序转变为 PWA 以提供离线访问和更好的用户体验。

vuex如何实现持久化?

  1. 手动持久化:

    • 将 state 中的数据存储到 localStorage 中,以便在页面刷新后仍然可以访问。
    • 通过监听 window 对象的 beforeunload 事件,将 state 中的数据存储到 localStorage 中。
  2. 使用插件:

    • 使用 vuex-persistedstate 插件来实现持久化。
    • vuex-persistedstate 插件会将 store 中的数据映射到本地环境中,从而实现持久化。
    • 它支持多种存储引擎,如 localStoragesessionStoragecookie 等。
  3. 原理:

    • Vuex 的状态是响应式的,当状态发生变化时,所有依赖于它的组件都会重新渲染。
    • Vuex 的状态是保存在内存中的,因此在页面刷新后,状态会被重置。
    • 为了解决这个问题,我们需要将状态保存到本地存储中。这样,在页面刷新后,我们可以从本地存储中恢复状态。

自定义组件中的v-model?

v-model 是 Vue 中的一个指令,用于在自定义组件中实现双向数据绑定。它是 Vue 的语法糖,本质上是通过自定义标签的属性传递和接收数据。

// 父组件
<template>
  <div>
    <custom-component v-model="data"></custom-component>
    <p>父组件中的数据:{{ data }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      data: ''
    }
  },
  components: {
    CustomComponent
  }
}
</script>
// 子组件
<template>
  <div>
    <input :value="value" @input="$emit('update:value', $event.target.value)">
  </div>
</template>

<script>
export default {
  model: {
    prop: 'value',
    event: 'update:value'
  },
  props: {
    value: String
  }
}
</script>

vue获取event对象的方式?

方法一: 默认获取

在方法中不填写参数时,默认第一个参数就是 event 对象。

<template>
  <div>
    <button @click="onClick">点击</button>
  </div>
</template>

<script>
export default {
  methods: {
    onClick(e) {
      console.log(e);
    }
  }
}
</script>

方法二: 特殊变量 $event

事件处理 — Vue.js (vuejs.org)

<template>
  <div>
    <button @click="onClick('hello', $event)">点击</button>
  </div>
</template>

<script>
export default {
  methods: {
    onClick(str, e) {
      console.log(str, e);
    }
  }
}
</script>

vue父子组件的通信方式?ref的弊端?如何使依赖注入传递的数据保持响应式?

  • props / $emit
  • provide / inject
  • $attrs / $listeners
  • ref / $ref
  • $parent / $children
  • vuex / pinia

ref的缺点主要是破坏了单向数据流,但它拿到的数据是响应式的;$parent / $children不仅破坏了单向数据流,而且还不是响应式的。

使依赖注入传递的数据保持响应式的方法:

  1. 直接传入整个父组件的实例:vue2的this就是个响应式数据。如果我们直接在父元素中提供依赖this,那么后代组件就能获得响应式。
  2. 函数/对象式的方式传入:比方说 provide 传递的是父组件的 name 这个变量,那么可以 parentName: () => this.name,或者 parentName: {name: this.name}.
  3. Vue-observable,使用API来创建一个响应式数据然后传递,类似的Vue3可以通过ref/reactive创建的数据传递下去就是响应式的。

vue父子组件的生命周期执行顺序?

加载渲染过程:

  1. 父组件 beforeCreate
  2. 父组件 created
  3. 父组件 beforeMount
  4. 子组件 beforeCreate
  5. 子组件 created
  6. 子组件 beforeMount
  7. 子组件 mounted
  8. 父组件 mounted

更新过程:

  1. 父组件 beforeUpdate
  2. 子组件 beforeUpdate
  3. 子组件 updated
  4. 父组件 updated

销毁过程:

  1. 父组件 beforeDestroy
  2. 子组件 beforeDestroy
  3. 子组件 destroyed
  4. 父组件 destoryed

vue中的修饰符有哪些?有没有使用过sync修饰符?

vue实现登录的逻辑?

  1. 登录表单校验
  2. 人类行为验证(简历上项目用的开源的 SliderCaptcha
  3. 调用 pinia 的登录 action 进行登录,所有用户登录行为将被放入到 pinia 中。
  4. 第一次登录时,前端调用后端的登录接口,发送用户名和密码,密码通过 md5 加密。
  5. 前端拿到 token 后,将其存储到 localStorage 和 pinia 中,并跳转路由页面。
  6. 此后前端每次跳转路由时,就判断 localStorage 中有无 token,没有则跳转到登录页面,有则跳转到对应的路由页面。
  7. 前端每次调用后端接口时,都要在请求头中携带 token
  8. 后端判断请求头中有无 token:
    • header 中存在 token:验证 token 的合法性,成功则返回前端请求的数据;失败(如 token 过期)就返回 401 状态码(401 Unauthorized
    • header 中不存在 token:同样返回 401 状态码
  9. 如果有请求返回了 401 状态码,则清除 token 信息并跳转到登陆页面。

vue的菜单权限和按钮权限?

推荐一篇整理的很好的文章:

面试官:Vue要做权限管理该怎么做?控制到按钮级别的权限怎么做?

代码题

js实现版本号排序

// 示例
var versions = ['2.1.0.1', '0.402.1', '10.2.1', '5.1.2', '1.0.4.5']
输出: ['10.2.1', '5.1.2', '2.1.0.1', '1.0.4.5', '0.402.1']
const versions = ['2.1.0.1', '0.402.1', '10.2.1', '5.1.2', '1.0.4.5'];

versions.sort((a, b) => {
  const partsA = a.split('.').map(Number);
  const partsB = b.split('.').map(Number);

  for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
    const partA = partsA[i] || 0;
    const partB = partsB[i] || 0;

    if (partA !== partB) {
      return partB - partA;
    }
  }

  return 0;
});

使用js补全代码

function add(){

}

add(1)(1)(1)() //3

add(1)(2)(3)(4) //10

add(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)() //10

这道题我不确定是不是题目中 add(1)(2)(3)(4) 这个地方最后少打了个括号?当时没意识到跟面试官提出疑惑,想了半天没想明白。

function add(num) {
  let sum = num;

  function addNext(nextNum) {
    if (nextNum === undefined) {
      return sum;
    } else {
      sum += nextNum;
      return addNext;
    }
  }

  return addNext;
}

console.log(add(1)(1)(1)()); // 输出 3
console.log(add(1)(2)(3)(4)); // 输出 10
console.log(add(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)()); // 输出 10