中软国际 - 前端面试

面试时间:2023-02-21

公司全称:中软国际科技服务有限公司(分公司)

公司性质:人力外派 💥

公司位置:广州天河区广东长线大厦1

面试题

防抖与节流的理解?各自的应用场景?
查看答案

防抖:在一次操作过程中,如果有新的操作则重新刷新定时器。应用:输入框输入后延迟自动搜索。

节流:前一次操作未完成时无法开启下一次操作。应用:下拉刷新和上拉加载更多。


浅拷贝与深拷贝的理解
查看答案

浅拷贝:拷贝对象的引用,对于复杂数据类型而言拷贝后的数据更改会影响原数据。

深拷贝:创建一块新的内存空间用于存储拷贝后的数据,拷贝数据与原数据由于地址不同,所以互不影响


this 指向的几种情况
查看答案

大多数情况下,函数调用方式决定了 this 的指向。

全局环境中定义的函数,this 指向 window。

new 关键字创建的实例对象,this 指向这个实例对象。

如果使用 apply()、call()、bind() 进行借调操作,this 指向这些方法第一个参数所绑定的对象。

箭头函数由于没有 this,它内部的 this 指向外层函数的 this,如果外层函数也没有 this,逐层向上找,直到 window 对象为止。


单页应用与多页应用的区别
查看答案

单页:应用只有一个 HTML 作为入口,一开始只需要加载一次 JS、CSS 等资源。页面的切换都是由路由去完成组件的切换,仅刷新局部资源。但无法实现 SEO 且首屏加载相对较慢。

多页:包含多个独立页面的应用,访问每一个页面都必须重新加载 JS、CSS 等资源。页面跳转需要整个页面刷新,用户体验不友好。由于返回完整的页面内容,利于 SEO。


Vue 的优势
查看答案

渐进式:易上手,开发者可以从简单的组件开始,逐渐去搭建复杂的系统。

轻量级:框架体积小。

组件化:组件化开发,提高开发效率。

MVVM 数据双向绑定:模型、视图同步更新,减少 dom 操作。

高性能:虚拟 dom + diff 算法。

插件化:插件生态丰富。


谈谈你对渐进式的理解?
查看答案

学习时可以从某个很小的部分入手,循序渐进,在后续通过增量学习的方式扩充所需的项目功能。


Vue 父子组件如何传值?
查看答案

父传子:父组件通过在子组件上添加属性的方式传递数据,子组件通过 props 属性接收。

子传父:子组件通过 this.$emit('eventName', data) 回传事件的方式传递数据,父组件通过 @eventName='fn' 绑定事件函数接收。


Vue 组件封装过程
查看答案

将公共常用的部分提取出去。通过 props 接收父组件传递的数据,通过 this.$emit() 传递事件的方式将数据传递给父组件。


v-model 的实现原理
查看答案

通过 :value 绑定响应式数据,@input 触发事件获取当前 $event.target.value,再赋值给 :value 绑定的变量。


computed 与 watch 的区别
查看答案

computed 计算属性基于 data 中声明过或 props 传递过来的数据通过计算得到一个新值,新值会根据已知值得变化而变化,且 computed 具有缓存功能,多次使用同一个 computed 计算得属性值,只会执行一次 computed 内定义的 function,直到依赖项改变才会重新计算。

watch 监听属性可以用来监听 data、props、computed 内的数据变化,然后执行某些具体的业务操作,当属性变化时,监听的的回调函数会自动执行。

对于多个监听对象要进行同一操作,watch 需要监听多次,而 computed 只需要执行一次。 在执行异步或开销比较大的操作时,watch 方式更合适。


笔试题

题目1:实现 compareVersion 方法,用于比较两个版本号(version1、version2)。1) 如果version1 > version2,返回1;2)如果version1 < version2,返回-1;3)其他情况,返回0。版本号规则x.y.z,xyz均为大于等于0的整数,至少有x位

目标:

compareVersion('0.1', '1.1.1'); // 返回-1

compareVersion('13.37', '1.2 '); // 返回1

compareVersion('1.1', '1.1.0'); // 返回0

compareVersion('1.1', '1.1.1'); // 返回-1

查看答案
/**
 * 题目1:
 *
 * 问题:实现 compareVersion 方法,用于比较两个版本号(version1、version2)
 *      如果version1 > version2,返回1;
 *      如果version1 < version2,返回-1;
 *      其他情况,返回0。
 *      版本号规则`x.y.z`,xyz均为大于等于0的整数,至少有x位
 *
 * 目标:
 * ```js
 * compareVersion('0.1', '1.1.1'); // 返回-1
 * compareVersion('13.37', '1.2 '); // 返回1
 * compareVersion('1.1', '1.1.0'); // 返回0
 * compareVersion('1.1', '1.1.1'); // 返回-1
 * ```
 */
function compareVersion(version1, version2) {
  // ... 这里写代码实现
// 版本号字符串转成数字数组
  const arr1 = version1.split('.').map(Number)
  const arr2 = version2.split('.').map(Number)

  // 长度不同时补 0 以保证长度一致
  while (arr1.length < arr2.length) {
    arr1.push(0)
  }
  while (arr2.length < arr1.length) {
    arr2.push(0)
  }

  // 比较每一位数字的大小
  for (let i = 0; i < arr1.length; i++) {
    if (arr1[i] > arr2[i]) {
      return 1
    } else if (arr1[i] < arr2[i]) {
      return -1
    }
  }

  // 相等返回 0
  return 0
}

题目2:井字棋游戏。输入一个二维数组代表棋盘,其中『1』代表当前玩家的棋子,『0』代表没有棋子,『-1』代表对方玩家的棋子。若一方棋子在横、竖、斜方向连成排则为获胜,返回当前玩家是否胜出

示例:入参为 [[1,0,1],[1,-1,-1],[1,-1,0]] 时,返回 true

查看答案
/**
 * 题目2:
 *
 * 问题:井字棋游戏。输入一个二维数组代表棋盘,其中
 *     『1』代表当前玩家的棋子,『0』代表没有棋子,『-1』代表对方玩家的棋子。
 *      若一方棋子在横、竖、斜方向连成排则为获胜,返回当前玩家是否胜出。
 * 示例:入参为 [[1,0,1],[1,-1,-1],[1,-1,0]] 时,返回 true
 *
 */
function gameCheck(arr) {
  // ... 这里写代码实现
const len = arr.length
  // 检查行
  for (let i = 0; i < len; i++) {
    let count = 0
    for (let j = 0; j < len; j++) {
      if (arr[i][j] === 1) {
        count++
      }
      if (count === 3) {
        return true
      }
    }
  }
  // 检查列
  for (let j = 0; j < len; j++) {
    let count = 0
    for (let i = 0; i < len; i++) {
      if (arr[i][j] === 1) {
        count++
      }
      if (count === 3) {
        return true
      }
    }
  }
  // 检查 2 条对角线
  if (
    (arr[0][0] === 1 && arr[1][1] === 1 && arr[2][2] === 1) ||
    (arr[0][2] === 1 && arr[1][1] === 1 && arr[2][0] === 1)
  ) {
    return true
  }
  return false
}
Contributors: tanqin