前言
先说明下自身成分,双非二本,属于 debuff 拉满了,在之前的一个月中也面试了许多的中厂,自认为经验准备充分,于是4月2号去面试了字节的懂车帝实习岗位(这里后续会写一篇),第一次面试这种顶级大厂,结果还是实力不济,被丢进鱼塘......
来不及为死去的字节哀悼了,接下来就重整信心找了学长帮忙去投滴滴,流程很快,一面下来受益颇多,发现了自己的很多不足,项目经验不足,节后就约了二面,好家伙直接部门组长来面我,提前打好预防针说我们面试时间可能会长很多,最后手写的时候一边被怼一遍擦冷汗,手抖个不停,写到后面我连函数声明都忘了怎么写,脑子一团浆糊,面完之后才发现已经面试了三小时,手写就花了2个小时,中途还停了一下跟面试官说先冷静下,面试官虽然会怼我的错误之处,但是也一直在引导我去如何实现,也通过这次面试明白了自己是真的很需要打磨自己,把基础抓牢固,也感谢面试官一直陪我走完整个流程......
一、由于篇幅和记忆问题这里就只出列举这些,uu感兴趣可以自行查阅
经典项目拷打环节
jwt与token
css定位
js有哪些原生获取dom结构的方法
js常见方法
js数据类型以及判断方法
js宏任务和微任务有哪些
输入url的渲染过程
http和https
知道哪些加密方法(对称加密和非对称加密)
说说vue框架帮你做了什么事情
- 声明式渲染: 通过在模板中使用指令,可以将数据自动渲染到 DOM 中,而无需手动操作 DOM。
- 组件化开发: 将应用拆分为独立的可重用组件,这种组件化开发方式使得代码易于维护和复用。
- 响应式数据: Vue 使用响应式系统来跟踪所有数据的变化,并在数据变化时自动更新 DOM。
- 单文件组件: Vue 支持单文件组件,即将组件的模板、逻辑和样式都写在一个文件中。
- 指令和过滤器: 例如,v-bind 指令用于绑定属性,v-on 指令用于监听事件。
- 路由管理: Vue Router,用于管理单页面应用的路由。
- 状态管理: Vuex 用于管理应用的状态,使得状态的管理更加简单和可预测。
那cli帮你做了什么事情?vite呢?
Vue CLI: Vue CLI 是一个官方提供的 Vue.js 项目脚手架工具,它帮助开发者快速搭建基于 Vue.js 的项目,并提供了一系列的命令和插件,简化了项目的配置和管理。
-
项目初始化: 通过
vue create
命令可以快速初始化一个新的 Vue 项目。 -
项目管理: 例如,
vue serve
用于在开发环境中快速启动一个开发服务器,vue build
用于构建生产环境的代码,vue deploy
用于部署项目到不同的平台等。 -
插件系统: 例如可以安装 Vuex、Vue Router 等官方插件,也可以安装第三方插件。
-
配置扩展: 通过
vue.config.js
文件来对项目进行配置扩展,例如配置 webpack、babel 等构建工具。
Vite: Vite 提供更快的开发体验和更佳的构建性能。相比传统的基于 webpack 或者 Rollup 的构建工具,Vite 使用了一种全新的构建方式,称为原生 ES 模块动态引入。
-
快速开发: Vite 利用原生 ES 模块的特性,实现了按需编译和即时热更新。
-
支持多种框架: 虽然 Vite 不仅仅支持 Vue.js,还支持 React、Preact、Lit Element 等多种框架。
-
插件化配置: 可以通过安装插件来扩展 Vite 的功能。
-
优化构建性能: Vite 在构建过程中利用了现代浏览器的原生 ES 模块支持,实现了快速的构建和加载速度。
真记不得还有哪些了......
二、手写一个轮播图
面试官一开始问我知道哪些前端组件库我说用过 elementplus 和 vant ,用过 vant ?面试官一下来劲了,那你写一个轮播图吧!
刚刚听到这个手写我不知道是该庆幸还是悲哀,庆幸的是这个组件可太熟悉了,悲哀是真的没想到会让手写这玩意,没办法了,只能硬着头皮上了......
一开始的时候是处于一个半懵逼状态,我只知道平常我们调用轮播图组件的时候都是给 Swiper
标签设置属性,来实现各种功能,所以一开始也脑抽这么写了......
Vant 组件调用实例:
我写的......
js
<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>
当时也是脑抽,这么一写直接被面试官怒怼,直接说你先把父组件调用写完再谈轮播图......
这时候我抽风的脑子才醒悟过来,我是要封装一个组件而不是调用一个组件......
后来在面试官的帮助下才把轮播图写了一个大概......
被怼:
- 你总算明白了是要封装一个组件而不是调用一个组件(我在这卡了好久,我太菜了......)
- 你怎么把
defineProps
写成了defineprops,常见api你都记不住?(这里真不怪我,我写的时候电脑抽风,没有提示,全程代码摁打的) - 调用
watch
你不传参数?(后面急速改watchEffect
) - 你再看看你定时器取消是不是有问题?(继续改......)
- 变量命名都出错?(......)
没被怼的:
- 思路通了以后写的挺快,就是变量命名不规范
- 相加求余这点蛮重要
- 绑定
style
x轴平移还不错
就这么一边冒冷汗,手抖个不停地写了一个小时🐭🐭太菜了
源码:
js
// 轮播图组件 ./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>
js
// 父组件调用 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>
当用户点击按钮切换图片时,会调用 prev
和 next
方法,这两个方法会修改 currentIndex
的值,从而实现图片的切换。
-
模板部分 (
<template>
):- 通过动态绑定
:style
属性来实现图片的滑动效果。transform
属性通过修改translateX
来控制图片的水平偏移,从而实现图片的滑动效果。transition
属性用于定义过渡效果,使图片切换时具有动画效果。
- 通过动态绑定
-
脚本部分 (
<script setup>
):- 使用
ref
创建了响应式数据currentIndex
,它表示当前显示的图片索引。 - 定义了
prev
和next
方法,用于切换图片。这两个方法会根据按钮点击事件修改currentIndex
的值,实现上一张和下一张图片的切换。 - 使用了
watchEffect
监听props.auto
和props.time
的变化。当props.auto
的值为true
时,会启动一个定时器,定时调用next
方法来自动切换图片,并根据props.time
来设置定时器的间隔时间。当props.auto
的值变为false
时,会清除定时器停止自动播放。
- 使用
-
相加求余:
- 在
prev
和next
方法中,使用了(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
标签包裹的子元素也可以这么理解)
js
const tree = {
id: 1,
children: [
{
id: 2,
children: [
{
id: 3,
children: [
{
id: 4,
children: [],
},
],
},
{
id: 5,
children: [],
},
],
},
{
id: 6,
children: [],
},
],
};
能想到这里那么这题就迎刃而解了,就是遍历树来找id并返回结构嘛~
结果我是这么写的
js
// 深度优先搜索
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
你是怎么调用的? 😫😫
js
let box = document.getElementByid('box')
然后继续改成这样的:
js
// 深度优先搜索
Function.prototype.findIdDfs(tree, id) {};
然后继续被批,你调用原型你怎么获得tree你告诉我?
用this获取对象......
写完后......
面试官:这是什么思路
我:深度优先遍历
面试官:那你再用广度写下
🐭🐭再次洗掉......
源码
js
// 深度优先搜索
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小时,最后反问环节,老师说我实战太少,基础不扎实,🐭🐭泪目
不管怎么活每次面试都是一次磨砺,下次继续努力吧~