B 站和腾讯的实习生面试总结

大家好,我是刘布斯。

最近很多公司都在招前端实习生,我们也正好分享一篇大厂实习生的面经,希望大家能早日找到心仪的工作。

浅聊一下

最近的这两个礼拜里,我经历了哔哩哔哩的两次面试,和腾讯的一次面试(均在等结果中),因为是大三找实习的情况,所以题目不是很难...上着外教课,闲来无事做做总结...

B 站一面

自我介绍

自我介绍少不了,我在之前的文章中也提到过,要讲明白: 我是谁+从哪里来+我做过什么+有什么成绩+为什么能胜任...

介绍一下项目

先简单介绍了一下我的小 demo,主要是做了一个类似朋友圈的一个功能的 demo,使用了 Vant 组件来上传我们的图片,接着说我在另一个项目中做的大文件上传。

后续还问到我的文件是以一个什么类型在流通以及我是如何传给后端的等等。

视差滚动

我在自我介绍的时候提到了哔哩哔哩首页的视差滚动的效果,于是让我说说视差滚动的原理。

列表循环

给你一个数组,数组中的数据为树形结构(其实是一个多级列表),要你在页面上渲染出这个多级菜单

当时有点没明白题目的意思,然后说了一下递归的一个思路,接着面试官就说行行行,那我们接着下一道

版本号排序

有这么一些版本号:

let arr = [
    'v1.0.1-beta.1.1',
    'v1.21.1-cr.2.1',
    'v1.1.01-alpha.1',
    'v1.1.0'
]

其中 cr>beta>alpha,要你实现一个函数,传入两个字符串,返回版本号大的那个

这里主要的难点是如何去处理后面的单词,我们可以使用

let obj = {
    cr:-1,
    beta:-2,
    alpha:-3
}

当我们要比较单词大小的时候,可以使用以下方式来进行对比

return obj[cr] > obj[beta]

想明白这点的话其他的步骤就非常简单了...

二叉树的遍历

在反问的时候和面试官聊的比较 high,于是面试官又给我出了两个题目

一层一层一次输出一个二叉树的所有结点

二叉树的层序遍历秒了...

然后又问如何不使用递归来进行深度优先遍历

使用栈的方式,有子节点就入栈,没有就出栈...

一面大概就这些内容了,面了一个小时十分钟...

B 站二面

大概等了四天,通知我 B 站二面,我之前还以为 G 了...

自我介绍

在这里花费了比较久的时间聊了一下我的学习方法,学习历程和学习计划,面试官问的比较详细,比如为什么会想要学习前端(之前搞 java)、自己比起其他竞争者的优点等等...

项目

先讲的是我的 jwt 的登录模块,等我噼里啪啦介绍完以后开始问:

  1. jwt 是由什么组成的
  2. jwt 解决了什么问题
  3. jwt 相对以前的模式有什么优点,或者说以前的 session+cookie 有什么缺点

我记得我在前面的文章中说过了,这里就不详细展开讲了...

输入 url 到页面渲染

从 DNS 域名解析开始说,直到回流重绘...

介绍完整个流程以后,问:当我们 DNS 域名解析拿到 ip 地址以后,是如何找到服务器的?

没回答出来,但是面试官给我做了详细的解释,也是类似 DNS 域名解析的一个过程,不过多了一个向下查找的过程

http

问了一下 http1.1 和 http2.0 的一个区别

一些优化(网络层、或者在项目中的优化)

对于网络层我了解的不多,主要聊了一下因为 TCP 慢启动和队头堵塞造成的一些问题,然后聊了一下使用 http3.0,抛弃 TCP 协议...讲完这个就问了我下一个题目了

服务端渲染

大概聊了一下我的了解,比如 vite、cli 脚手架在页面上看不见我们 div 中的结点,会导致 SEO 搜索不太顺利...

webpack 和 vite

我 webpack 使用较少,于是面试官直接跳过

React

我在前面提到,我最近在学习 React,面试官问我了解多少

我从 Vue 和 React 的一个比较学习说起,讲了一下 class 组件和函数式组件的响应式、生命周期、组件传值,顺便夹带一点 Vue 的东西在里面

节流

手写一个节流

到这里就基本结束了,面试官说你很欧克,但是我们只招一个,面完其他人作横向比较再通知结果/(ㄒ o ㄒ)/~~

腾讯一面

今天上午面的,面的是腾讯应用宝部门的前端实习生岗位,话说大厂都这么有个性吗?上来自我介绍都木有,直接上了五道题 😂,掘友们可以自己做做

第一题

给你一个字符串表达式,请你实现一个基本计算器来计算并返回他的值

第二题

完成搜索页

要求:

  • 实现点击搜索按钮以后,获取输入框最新值,调用 searchByKeyword 方法获取搜索结果
  • 实现用于展示搜索结果的列表组件,并在搜索区使用
  • 在列表组件中实现分页功能,每页五条数据
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>搜索页 - Vue</title>
    <script src="https://cdn.yyb.gtimg.com/exam/vue.global.js"></script>
  </head>
  <body>
    <div id="app" class="main-container">
      <div class="search-container">
        <search-input v-model:value="keyword" class="input"></search-input>
        <search-button></search-button>
      </div>

      <div class="result-container">
        搜索结果区
      </div>
    </div>
    <script>
      // 按钮组件
      const searchButton = {
        template`
          <button @click="$emit('search')">
            搜索
          </button>
        `
,
      };

      // 输入框组件
      const searchInput = {
        template`
          <input type="text" :value="value" @input="$emit('update:value', $event.target.value)" class="search-input"/>
        `
,
        props: ['value'],
      };

      const { createApp } = Vue;
      createApp({
        data() {
          return {
            keyword''
          }
        },
        components: {
          searchButton,
          searchInput,
        },
        methods: {
          // 根据关键字搜索,获得结果列表,为方便考试随机生成结果,可假想为内部调用了搜索接口
          searchByKeyword(keyword) {
            const min = 3;
            const max = 20;
            const resultLength = Math.round((max - min) * Math.random()) + min;
            return Array.from(Array(resultLength).keys()).map(() => ({
              titlethis.genRandomString(keyword, 5),
              contentthis.genRandomString(keyword, 20),
            }));
          },
          // 根据关键字生成指定长度的随机字符串
          genRandomString(keyword, length) {
            const randomString = Array.from(Array(length).keys()).map(() => String.fromCodePoint(Math.round(Math.random() * 20901) + 19968)).join('');
            const randomIndex = Math.floor(Math.random() * (randomString.length + 1));
            return randomString.slice(0, randomIndex) + keyword + randomString.slice(randomIndex);
          },
          console(e){
            console.log(e);
          }
        },
      }).mount('#app');
    
</script>
  </body>
  <style>
    .main-container {
      display: flex;
      align-items:center;
      flex-direction: column;
    }
    .search-container.result-container {
      display: flex;
      margin-top50px;
    }
    .search-input {
      margin-right10px;
      width300px;
    }
  
</style>
</html>

第三题

这是一个简易计算器,有一些 bug,请你找出来并且修改:

  • 在浏览器打开出现显示异常并且操作无反馈
  • 解决问题 1 后,计算器能正常输入了,但是不能正常运算,如输入“3+3=”无法计算出结果
  • 解决问题 2 以后,计算器除 0 会出现“Infinity”结果,且在该结果之后仍能添加数字进行操作,但是操作结果为 Infinity

我给的是已修正版本

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vue 3 Calculator</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/@vue/babel-plugin-jsx@1.2.2/dist/index.min.js"></script>
  <style>
    .calculator {
      max-width400px;
      margin50px auto;
      border1px solid #ccc;
      border-radius5px;
      padding10px;
    }

    .display {
      padding10px;
      margin-bottom10px;
      background-color#f2f2f2;
      text-align: right;
      border1px solid #ccc;
      border-radius5px;
    }

    .button {
      width23%;
      padding10px;
      margin1%;
      font-size1.2em;
      border1px solid #ccc;
      border-radius5px;
      background-color#e7e7e7;
      cursor: pointer;
    }

    .button:hover {
      background-color#d7d7d7;
    }

    .row {
      display: flex;
      justify-content: space-between;
    }
  
</style>
</head>
<body>
  <div id="app" class="calculator">
    <div class="display">{{ display }}</div>
    <div class="row">
      <button class="button" @click="clear">C</button>
      <button class="button" @click="sign">±</button>
      <button class="button" @click="percent">%</button>
      <button class="button" @click="setOperator('/')">÷</button>
    </div>
    <div class="row">
      <button class="button" @click="append('7')">7</button>
      <button class="button" @click="append('8')">8</button>
      <button class="button" @click="append('9')">9</button>
      <button class="button" @click="setOperator('*')">x</button>
    </div>
    <div class="row">
      <button class="button" @click="append('4')">4</button>
      <button class="button" @click="append('5')">5</button>
      <button class="button" @click="append('6')">6</button>
      <button class="button" @click="setOperator('-')">-</button>
    </div>
    <div class="row">
      <button class="button" @click="append('1')">1</button>
      <button class="button" @click="append('2')">2</button>
      <button class="button" @click="append('3')">3</button>
      <button class="button" @click="setOperator('+')">+</button>
    </div>
    <div class="row">
      <button class="button" @click="append('0')">0</button>
      <button class="button" @click="append('.')">.</button>
      <button class="button" style="flex: 2;" @click="calculate">=</button>
    </div>
  </div>

<script>
  const { createApp, ref, computed } = Vue;
  createApp({
    setup() {
      const current = ref('');
      const previous = ref(null);
      const operator = ref(null);
      const operatorClicked = ref(false);

      const display = computed(() => current.value || '0');

      function clear() {
        current.value = '';
      }

      function sign() {
        current.value = current.value.charAt(0) === '-' ? current.value.slice(1) : `-${current.value}`;
      }

      function percent() {
        current.value = `${parseFloat(current.value) / 100}`;
      }

      function append(number) {
        if (operatorClicked.value) {
          current.value = '';
          operatorClicked.value = false;
        }
        console.log(current.value,number);
        current.value = current.value === Infinity?`${number}`:`${current.value}${number}`;
      }

      function setPrevious() {
        previous.value = current.value;
        operatorClicked.value = true;
      }

      function calculate() {
        let result;
        const currentNumber = parseFloat(current.value);
        const previousNumber = parseFloat(previous.value);

        if (isNaN(previousNumber) || isNaN(currentNumber)) {
          return;
        }

        switch (operator.value) {
          case '+':
            result = previousNumber + currentNumber;
            break
          case '-':
            result = previousNumber - currentNumber;
            break
          case '*':
            result = previousNumber * currentNumber;
            break
          case '/':
            result = previousNumber / currentNumber;
            break
          default:
            return;
        }

        current.value = result;
        operator.value = null;
        previous.value = null;
      }

      function setOperator(op) {
        if (current.value === '') return;
        if (previous.value !== null) {
          calculate();
        } else {
          setPrevious();
        }

        operator.value = op;
        operatorClicked.value = true;
      }

      return {
        display,
        clear,
        sign,
        percent,
        append,
        calculate,
        setOperator
      };
    }
  }).mount('#app');
</script>
</body>
</html>

第四题

下面代码段功能如下,点击查询按钮,从后台服务器接口和 URL 参数中获取指定字段的数据显示到界面上,请从代码风格规范、实现逻辑、方案设计、性能、安全等不同方面考虑、列出该代码存在的问题,并简单给出解决方案

<button id="btn1" onclick="clickFunction">查询</button>
<p id="text1"></p>
<script>
var DOC=document;
var clickFunction=function({
  var BTN=DOC.getElementById('#btn1');
  var TEXT=DOC.getElementById('#text1')

  var getUrlParam=function(k){
      var url=window.location.href;
      var params=url.split("&")
      for(var i=0;i<params.length;i++){
          var param = params[i].split("=");
          if(k=param[0]){
            return param[1]
          }
      }
  }
  getDataFromServer(function(d){
      var obj=JSON.parse(d);
      BTN.innerHTML="已查询";
      TEXT.innerHTML=obj.data[0].text+" "+getUrlParam("text")
  });
}
</script>

第五题

赛马:25 匹马,5 个赛道,每次只能同时有 5 匹马跑,在无法计时的前提下,最少比赛几次选出最快的前三名的马?

一个小时的做题时间,我写完了两道,还有十分钟,连忙和面试官说时间不太够,我来给您讲讲我的思路,讲完以后面试官又问我对其他没写的题的思路,然后又讲了一会,面试时长一个半小时,面的我饥肠辘辘...

最后

还没有使用过我们刷题网站(https://fe.ecool.fun/)或者刷题小程序的同学,如果近期准备或者正在找工作,千万不要错过,题库主打无广告和更新快哦~。

老规矩,也给我们团队的辅导服务打个广告。

原文地址:https://juejin.cn/post/7356772896046284836