字节无缘后,迎来了滴滴二面,好家伙鏖战三小时!

前言

先说明下自身成分,双非二本,属于 debuff 拉满了,在之前的一个月中也面试了许多的中厂,自认为经验准备充分,于是4月2号去面试了字节的懂车帝实习岗位(这里后续会写一篇),第一次面试这种顶级大厂,结果还是实力不济,被丢进鱼塘……

来不及为死去的字节哀悼了,接下来就重整信心找了学长帮忙去投滴滴,流程很快,一面下来受益颇多,发现了自己的很多不足,项目经验不足,节后就约了二面,好家伙直接部门组长来面我,提前打好预防针说我们面试时间可能会长很多,最后手写的时候一边被怼一遍擦冷汗,手抖个不停,写到后面我连函数声明都忘了怎么写,脑子一团浆糊,面完之后才发现已经面试了三小时,手写就花了2个小时,中途还停了一下跟面试官说先冷静下,面试官虽然会怼我的错误之处,但是也一直在引导我去如何实现,也通过这次面试明白了自己是真的很需要打磨自己,把基础抓牢固,也感谢面试官一直陪我走完整个流程……

一、由于篇幅和记忆问题这里就只出列举这些,uu感兴趣可以自行查阅

经典项目拷打环节

jwt与token

css定位

js有哪些原生获取dom结构的方法

js常见方法

js数据类型以及判断方法

js宏任务和微任务有哪些

输入url的渲染过程

http和https

知道哪些加密方法(对称加密和非对称加密)

说说vue框架帮你做了什么事情

  1. 声明式渲染: 通过在模板中使用指令,可以将数据自动渲染到 DOM 中,而无需手动操作 DOM。
  2. 组件化开发: 将应用拆分为独立的可重用组件,这种组件化开发方式使得代码易于维护和复用。
  3. 响应式数据: Vue 使用响应式系统来跟踪所有数据的变化,并在数据变化时自动更新 DOM。
  4. 单文件组件: Vue 支持单文件组件,即将组件的模板、逻辑和样式都写在一个文件中。
  5. 指令和过滤器: 例如,v-bind 指令用于绑定属性,v-on 指令用于监听事件。
  6. 路由管理: Vue Router,用于管理单页面应用的路由。
  7. 状态管理: Vuex 用于管理应用的状态,使得状态的管理更加简单和可预测。

那cli帮你做了什么事情?vite呢?

Vue CLI: Vue CLI 是一个官方提供的 Vue.js 项目脚手架工具,它帮助开发者快速搭建基于 Vue.js 的项目,并提供了一系列的命令和插件,简化了项目的配置和管理。

  1. 项目初始化: 通过 vue create 命令可以快速初始化一个新的 Vue 项目。

  2. 项目管理: 例如,vue serve 用于在开发环境中快速启动一个开发服务器,vue build 用于构建生产环境的代码,vue deploy 用于部署项目到不同的平台等。

  3. 插件系统: 例如可以安装 Vuex、Vue Router 等官方插件,也可以安装第三方插件。

  4. 配置扩展: 通过 vue.config.js 文件来对项目进行配置扩展,例如配置 webpack、babel 等构建工具。

Vite: Vite 提供更快的开发体验和更佳的构建性能。相比传统的基于 webpack 或者 Rollup 的构建工具,Vite 使用了一种全新的构建方式,称为原生 ES 模块动态引入

  1. 快速开发: Vite 利用原生 ES 模块的特性,实现了按需编译和即时热更新。

  2. 支持多种框架: 虽然 Vite 不仅仅支持 Vue.js,还支持 React、Preact、Lit Element 等多种框架。

  3. 插件化配置: 可以通过安装插件来扩展 Vite 的功能。

  4. 优化构建性能: Vite 在构建过程中利用了现代浏览器的原生 ES 模块支持,实现了快速的构建和加载速度。

真记不得还有哪些了……

二、手写一个轮播图

面试官一开始问我知道哪些前端组件库我说用过 elementplusvant ,用过 vant ?面试官一下来劲了,那你写一个轮播图吧!

刚刚听到这个手写我不知道是该庆幸还是悲哀,庆幸的是这个组件可太熟悉了,悲哀是真的没想到会让手写这玩意,没办法了,只能硬着头皮上了……

一开始的时候是处于一个半懵逼状态,我只知道平常我们调用轮播图组件的时候都是给 Swiper 标签设置属性,来实现各种功能,所以一开始也脑抽这么写了……

Vant 组件调用实例:

字节无缘后,迎来了滴滴二面,好家伙鏖战三小时!

我写的……

<template>
    <button @click="prev">上一张</button>
    <button @click="next">下一张</button>
    <div>
        <div :list="list" :auto="true" :time="1000" v-for="(item, index) in props.list" :key="index">
            <img :src="item" alt="" />
        </div>
        <div class="swiper"></div>
    </div>
</template>

当时也是脑抽,这么一写直接被面试官怒怼,直接说你先把父组件调用写完再谈轮播图……

这时候我抽风的脑子才醒悟过来,我是要封装一个组件而不是调用一个组件……

后来在面试官的帮助下才把轮播图写了一个大概……

被怼:

  1. 你总算明白了是要封装一个组件而不是调用一个组件(我在这卡了好久,我太菜了……)
  2. 你怎么把defineProps写成了defineprops,常见api你都记不住?(这里真不怪我,我写的时候电脑抽风,没有提示,全程代码摁打的)
  3. 调用watch你不传参数?(后面急速改watchEffect
  4. 你再看看你定时器取消是不是有问题?(继续改……)
  5. 变量命名都出错?(……)

没被怼的:

  1. 思路通了以后写的挺快,就是变量命名不规范
  2. 相加求余这点蛮重要
  3. 绑定stylex轴平移还不错

就这么一边冒冷汗,手抖个不停地写了一个小时🐭🐭太菜了

源码:

// 轮播图组件 ./components/Swiper.vue
<template>
    <button @click="prev">上一张</button>
    <button @click="next">下一张</button>
    <div>
        <div class="swiper-item" v-for="(item, index) in props.list" :key="index"
            :style="{ transform: `translateX(${currentIndex * -140}px)`, transition: 'transform 0.5s ease', }">
            <img :src="item" alt="" />
        </div>
        <div class="swiper"></div>
    </div>
</template>

<script setup>
import { ref, watchEffect } from "vue";
const props = defineProps({
    list: {
        type: Array,
    },
    auto: {
        type: Boolean,
        default: true,
    },
    time: {
        type: Number,
        default: 3000,
    },
});

const currentIndex = ref(0);
const isPaused = ref(false);

const prev = () => {
    currentIndex.value =
        (currentIndex.value - 1 + props.list.length) % props.list.length;
    console.log(currentIndex.value);
};

const next = () => {
    currentIndex.value =
        (currentIndex.value + 1 + props.list.length) % props.list.length;
    console.log(currentIndex.value);
};

watchEffect(() => {
    let timer;
    if (props.auto) {
        timer = setInterval(() => {
            next();
        }, props.time);
    } else if (timer) {
        clearInterval(timer);
    }
});
</script>

<style lang="css" scoped>
* {
    margin: 0;
    padding: 0;
}

.swiper-item {
    float: left;
}

img {
    height: 100px;
    width: 100px;
    margin: 20px;
}

.swiper {
    position: absolute;
    width: 140px;
    height: 140px;
    border: 1px solid #000;
    overflow: hidden;
}
</style>
// 父组件调用 SwipTest.vue
<template>
  <swip :list="list" :auto="true" :time="1000" />
</template>

<script setup>
import swip from "./components/Swiper.vue";

const list = [
  "https://yanxuan-item.nosdn.127.net/cac68a7880bec1c72dcfce112d10e955.png",
  "https://yanxuan-item.nosdn.127.net/06a158d2888b20383a466227e39bbbc7.jpg",
  "https://yanxuan.nosdn.127.net/8f8092d5bf6a133a8cb59ab7b9f790e9.png",
  "https://yanxuan-item.nosdn.127.net/eac6c40fdb0f977fdf80048d7b181ffa.png",
  "https://yanxuan-item.nosdn.127.net/f881cfe7de9a576aaeea6ee0d1d24823.jpg",
];
</script>

<style lang="scss" scoped></style>

当用户点击按钮切换图片时,会调用 prevnext 方法,这两个方法会修改 currentIndex 的值,从而实现图片的切换。

  1. 模板部分 (<template>):

    • 通过动态绑定 :style 属性来实现图片的滑动效果。transform 属性通过修改 translateX 来控制图片的水平偏移,从而实现图片的滑动效果。transition 属性用于定义过渡效果,使图片切换时具有动画效果。
  2. 脚本部分 (<script setup>):

    • 使用 ref 创建了响应式数据 currentIndex,它表示当前显示的图片索引。
    • 定义了 prevnext 方法,用于切换图片。这两个方法会根据按钮点击事件修改 currentIndex 的值,实现上一张和下一张图片的切换。
    • 使用了 watchEffect 监听 props.autoprops.time 的变化。当 props.auto 的值为 true 时,会启动一个定时器,定时调用 next 方法来自动切换图片,并根据 props.time 来设置定时器的间隔时间。当 props.auto 的值变为 false 时,会清除定时器停止自动播放。
  3. 相加求余:

    • prevnext 方法中,使用了 (currentIndex.value - 1 + props.list.length) % props.list.length 来计算下一个要显示的图片索引。这是为了实现循环播放效果。当 currentIndex 等于 0 时,再向前切换就会回到最后一张图片;当 currentIndex 等于 props.list.length - 1 时,再向后切换就会回到第一张图片。

三、手写getElementById

好不容易写完后听到这个我又蒙了,这也能手写?……

我们都知道dom结构本质是一种树状结构,所以这题的本意就是让你获树状结构的id值并返回改结构……

字节无缘后,迎来了滴滴二面,好家伙鏖战三小时!

简单可以将dom结构转化为以下这种形式,就拿ul标签来说,每个ul都有属于自己的id值,其ul标签下还有许多li标签,那么可以理解为li标签在ul中的children属性中(同理被div标签包裹的子元素也可以这么理解)

const tree = {
  id: 1,
  children: [
    {
      id: 2,
      children: [
        {
          id: 3,
          children: [
            {
              id: 4,
              children: [],
            },
          ],
        },
        {
          id: 5,
          children: [],
        },
      ],
    },
    {
      id: 6,
      children: [],
    },
  ],
};

能想到这里那么这题就迎刃而解了,就是遍历树来找id并返回结构嘛~

结果我是这么写的

// 深度优先搜索
Function findIdDfs(tree, id) {
  if (!tree) return null;
  if (tree.id === id) {
    return this;
  }

  if (tree.children) {
    for (let i = 0; i < tree.children.length; i++) {
      const findtree = tree.children[i].findIdDfs(id);
      if (findtree) {
        return findtree;
      }
    }
  }
  return null;
};

面试官说你用getElementById 你是怎么调用的? 😫😫

let box = document.getElementByid('box')

然后继续改成这样的:

// 深度优先搜索
Function.prototype.findIdDfs(tree, id) {};

然后继续被批,你调用原型你怎么获得tree你告诉我?

用this获取对象……

写完后……

面试官:这是什么思路

我:深度优先遍历

面试官:那你再用广度写下

🐭🐭再次洗掉……

源码

// 深度优先搜索
Object.prototype.findIdDfs = function (id) {
  if (!this) return null;
  if (this.id === id) {
    return this;
  }

  if (this.children) {
    for (let i = 0; i < this.children.length; i++) {
      const findtree = this.children[i].findIdDfs(id);
      if (findtree) {
        return findtree;
      }
    }
  }
  return null;
};

console.log(tree.findIdDfs(5));

// 广度优先搜索
Object.prototype.findIdBfs = function (id) {
  const queue = [this];
  while (queue.length > 0) {
    const node = queue.shift();
    if (node.id === id) {
      return node;
    }

    if (node.children && node.children.length > 0) {
      for (let i = 0; i < node.children.length; i++) {
        queue.push(node.children[i]);
      }
    }
  }
  return null;
};

console.log(tree.findIdBfs(5));

本人实力太菜,前面轮播图写了一个多小时,写到这里的时候已经面了3小时,最后反问环节,老师说我实战太少,基础不扎实,🐭🐭泪目

不管怎么活每次面试都是一次磨砺,下次继续努力吧~

原文链接:https://juejin.cn/post/7356778082824372250 作者:Aoew

(0)
上一篇 2024年4月13日 上午10:22
下一篇 2024年4月13日 上午10:32

相关推荐

发表回复

登录后才能评论