Skip to content

磐松资产-前端实习-一面

时间:一面11.21.25 时长:30min

1 考试信息

使用ShowMeBug这平台来考,双机位的摄像头监考,考的东西不太难,但是我有点忘了。大题的最后一道编程题,那个系统不太会用,浪费了不少时间。

2 考试内容(一共17道)

有点忘了

选择

  1. reduce,累加的用法
  2. 对象的字面量创建
  3. Array.from的用法,它能做什么
  4. 将一个数组转化为使用逗号分隔的字符串
  5. 如何为对象添加一个方法

填空

  1. 初始化一个空对象的方法
  2. 连接字符串的符号
  3. 忘了

大题(三道)

  1. 分析事件循环机制
  2. 编程,点击背景将一个三角型的颜色由红转换为粉色

3 参考答案

以下是前端笔试题目对应的参考答案,兼顾基础知识点准确性和实际应用场景,符合面试笔试答题规范:

一、选择题(含解析)

1. reduce 累加的用法

答案reduce 是数组方法,用于对数组元素逐个处理并累加得到最终结果,核心语法:arr.reduce((acc, curr, idx, arr) => {}, initialValue)

  • 关键参数:
    • 回调函数:接收4个参数(acc 累计值、curr 当前元素、idx 当前索引、arr 原数组)
    • initialValue(可选):累计值初始值,不传递则默认以数组第1个元素为初始 acc
  • 示例(数组求和):
    javascript
    const arr = [1, 2, 3];
    const sum = arr.reduce((acc, curr) => acc + curr, 0); // 结果:6

2. 对象的字面量创建

答案:使用 {} 直接定义对象属性和方法(ES6+ 支持简洁语法),示例:

javascript
// 基础字面量创建
const person = {
  name: "张三", // 属性键值对
  age: 20,
  sayHi: function() { // 方法
    console.log(`Hi, ${this.name}`);
  }
};

// ES6 简洁语法(方法简写、属性简写)
const name = "李四";
const student = {
  name, // 属性简写(键名与变量名一致)
  study() { // 方法简写(省略 function)
    console.log("学习中");
  }
};

3. Array.from 的用法

答案:将「类数组对象」或「可迭代对象(Iterable)」转为真正的数组,支持映射和绑定this,语法:Array.from(arrayLike, mapFn?, thisArg?)

  • 核心功能:
    1. 转换类数组(含 length 属性的对象,如 arguments、DOM 集合)
    2. 转换可迭代对象(字符串、Set、Map 等)
    3. 第二个参数(可选):映射函数(类似 map
  • 示例:
    javascript
    // 转换 DOM 集合
    const divs = document.querySelectorAll("div");
    const divArr = Array.from(divs); // 转为数组
    
    // 转换字符串(每个字符为数组元素)
    Array.from("abc"); // ['a', 'b', 'c']
    
    // 带映射函数(数组去重+平方)
    const set = new Set([1, 2, 2, 3]);
    Array.from(set, x => x * x); // [1, 4, 9]

4. 将数组转化为逗号分隔的字符串

答案:使用数组方法 join(',')(最简洁高效),示例:

javascript
const arr = ["苹果", "香蕉", "橙子"];
const str = arr.join(','); // 结果:"苹果,香蕉,橙子"

// 特殊情况:空数组返回空串
[].join(','); // ""

5. 为对象添加一个方法

答案:3种常用方式,优先推荐ES6简洁语法:

javascript
const obj = {};

// 方式1:字面量创建时直接定义(初始化阶段)
const obj1 = {
  eat() { console.log("吃饭"); } // ES6 方法简写
};

// 方式2:后期通过点语法/方括号添加(动态添加)
obj2.say = function() { console.log("说话"); };
obj2["run"] = () => console.log("跑步"); // 方括号支持动态键名

// 方式3:通过 Object.assign 批量添加
Object.assign(obj3, {
  jump() { console.log("跳跃"); }
});

二、填空题(含核心答案)

1. 初始化一个空对象的方法

答案(至少2种常用方式):

  • const obj = {};(最简洁,推荐)
  • const obj = new Object();(构造函数方式)
  • const obj = Object.create({});(创建原型为指定对象的空对象)
  • const obj = Object.create(null);(创建无原型的空对象)

2. 连接字符串的符号

答案

  • + 运算符(基础用法):"a" + "b" + 123"ab123"
  • 模板字符串 `(ES6 推荐,支持换行和变量):const name = "张三"; 你好,${name}

三、大题(详细解析+代码)

1. 事件循环机制(Event Loop)分析

核心结论:JS 是单线程语言,事件循环是解决「异步任务执行顺序」的核心机制,分为「浏览器环境」和「Node 环境」,前端重点关注浏览器环境。

浏览器环境事件循环流程:

  1. 执行栈(Call Stack):同步代码按顺序进入执行栈,执行完后出栈;
  2. 异步任务分类
    • 微任务(Microtasks):优先级高,执行栈空后立即执行所有微任务(队列清空才会执行宏任务)
      • 常见:Promise.then/catch/finallyqueueMicrotask()process.nextTick(Node 特有)
    • 宏任务(Macrotasks):优先级低,微任务执行完后执行1个宏任务(然后回到微任务检查)
      • 常见:setTimeout/setInterval、DOM 事件(如 click)、AJAX 请求、requestAnimationFrame
  3. 循环逻辑
    • 执行所有同步代码 → 执行栈空 → 执行所有微任务 → 取1个宏任务执行 → 执行栈空 → 重复上述步骤

示例代码分析(理解执行顺序):

javascript
console.log("1"); // 同步代码
setTimeout(() => console.log("2"), 0); // 宏任务
Promise.resolve().then(() => console.log("3")); // 微任务
console.log("4"); // 同步代码

// 执行顺序:1 → 4 → 3 → 2
// 解析:
// 1. 同步代码 "1"、"4" 先执行,输出 1、4;
// 2. 执行栈空,执行微任务 Promise.then,输出 3;
// 3. 微任务队列清空,执行1个宏任务 setTimeout,输出 2。

2. 编程题:点击背景切换三角形颜色(红→粉)

需求:页面背景可点击,点击后将三角形由红色转为粉色(再次点击可切换回红色,可选优化)。
实现思路

  • HTML:创建背景容器和三角形元素;
  • CSS:用 border 实现三角形(宽高为0,单边设颜色,其他透明),初始红色;
  • JS:给背景容器绑定点击事件,切换三角形的颜色(用 classList.toggle 或直接修改 style)。

完整代码(可直接运行)

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>三角形颜色切换</title>
  <style>
    /* 背景容器:占满屏幕,可点击 */
    .bg-container {
      width: 100vw;
      height: 100vh;
      background-color: #f5f5f5;
      display: flex;
      justify-content: center;
      align-items: center;
      cursor: pointer;
    }
    /* 三角形:用 border 实现 */
    .triangle {
      width: 0;
      height: 0;
      /* 初始红色:下三角(border-bottom 设颜色,其他透明) */
      border-left: 50px solid transparent;
      border-right: 50px solid transparent;
      border-bottom: 100px solid red; /* 红色初始值 */
      transition: border-color 0.3s ease; /* 过渡动画,优化体验 */
    }
    /* 粉色状态类 */
    .triangle.pink {
      border-bottom-color: pink;
    }
  </style>
</head>
<body>
  <div class="bg-container">
    <div class="triangle"></div>
  </div>
  <script>
    // 1. 获取 DOM 元素
    const bgContainer = document.querySelector('.bg-container');
    const triangle = document.querySelector('.triangle');

    // 2. 绑定点击事件
    bgContainer.addEventListener('click', () => {
      // 切换 pink 类:有则移除(红),无则添加(粉)
      triangle.classList.toggle('pink');
    });
  </script>
</body>
</html>

代码说明

  • 三角形实现:通过 border 透明边框叠加,仅底部边框设颜色,形成下三角;
  • 颜色切换:用 classList.toggle 简化逻辑,点击一次添加 pink 类(粉色),再点击移除(红色);
  • 优化点:添加 transition 过渡动画,颜色切换更流畅,提升用户体验。

4 复盘反思

考试我个人认为考的不太好,虽然选填的答案应该还可以,但是事件循环机制忘了,最后一道的三角形也没整出来,忘记边框还能这样用了。也没有进行充足的复习(Java快考试了),周一还有个字节的,周五考完试,周末我要好好复习一下,尽最大可能拿下这个(拿不下我还有下家😋😋😋)

另外笔试题全部都是js的题,尤其是es6的部分特别的多,以及常用的API考的都很多,没考css和html

>11.22.25 一面过了😋,周三下午二面(应该没有三面了吧)

磐松资产-前端实习-二面

时间:11/26/25 时长:46min左右

1 流程

  • 自我介绍
  • 提问
  • 反问

2 提问内容

  • 数组去重的方法

  • promise.allsettled和promise.all的区别❌️

  • 如何设计一个简单的事件总线(发布订阅)❌️

  • webpack与vite的区别

  • 如何进行Axios配置

  • 对于一刻短剧的滑动5个就重新刷新的设计原因

  • 抖音的视频是提前加载,预处理。点赞和收藏是写死的

  • 一刻短剧的性能优化

  • 视频的浏览记录历史保存(返回视频有历史播放进度)

  • 在项目中有没有使用provide与inject

  • 针对事件监听的节流处理

  • 你是如何确定当前播放的视频是哪一个的

  • 防抖的设置

  • 移动端优先的设计理念❌️

  • 你部署的CI/CD流程

  • 4k大屏,但是只能输出1080p,该如何避免缩放失真❌️

  • Tailwindcss和普通的css有什么优缺点

  • 介绍一下项目是如何进行Pinia状态管理的

  • localstorage

  • 主题切换该如何去做

  • 平时开发有使用什么好用的AI吗

  • 有了解过我们公司吗

  • 偏向的公司类型

  • 直属上级和你在代码上有意见,你该如何解决

  • 你喜欢什么样的工作环境

  • 对实习的期待或者希望学习到什么

  • 个人投递方向全是前端吗

  • 什么时间入职

  • 实习多久

3 参考答案

以下是按「技术类」「项目业务类」「个人求职类」分类的面试参考答案,兼顾实操性、逻辑性和面试表达场景,可根据自身实际经验调整细节:

一、技术类问题(突出实操性+核心逻辑)

1. 数组去重的方法(常用3种,按场景选择)

  • 基础高效版(推荐):[...new Set(arr)]Array.from(new Set(arr)),利用Set不可重复特性,简洁高效,时间复杂度O(n),但无法去重对象数组(仅适用于基本类型)。
  • 兼容低版本/精准控制版:arr.filter((item, index) => arr.indexOf(item) === index),利用indexOf返回首次出现索引,筛选唯一元素,可自定义去重规则(如对象数组可加条件)。
  • 性能优化版(大数据量):arr.reduce((acc, cur) => acc.includes(cur) ? acc : [...acc, cur], []),减少遍历次数,适合需同时处理其他逻辑(如数据转换)的场景。

2. Promise.all 与 Promise.allSettled 的区别

特性Promise.allPromise.allSettled
状态触发全部Promise resolved才resolved;任一rejected则立即rejected所有Promise完成(无论resolve/reject)后才resolved
返回结果成功:所有结果组成的数组;失败:第一个reject的原因每个Promise的结果对象数组(含status和value/reason)
适用场景依赖所有异步结果(如多接口并行获取后合并数据)无需依赖所有结果,需知道每个异步的执行状态(如批量请求统计成功/失败数)

3. 如何设计一个简单的事件总线(发布订阅模式)

核心是「事件中心+订阅/发布/取消订阅」三大功能,基于对象存储事件回调:

javascript
class EventBus {
  constructor() {
    this.events = {}; // 存储事件:{ eventName: [callback1, callback2] }
  }
  // 订阅事件
  on(eventName, callback) {
    if (!this.events[eventName]) this.events[eventName] = [];
    this.events[eventName].push(callback);
  }
  // 发布事件(传参)
  emit(eventName, ...args) {
    const callbacks = this.events[eventName];
    if (callbacks) callbacks.forEach(cb => cb(...args));
  }
  // 取消订阅(单个回调/全部回调)
  off(eventName, callback) {
    const callbacks = this.events[eventName];
    if (!callbacks) return;
    if (callback) {
      this.events[eventName] = callbacks.filter(cb => cb !== callback);
    } else {
      delete this.events[eventName]; // 移除整个事件
    }
  }
}
// 使用:const bus = new EventBus(); bus.on('xxx', ()=>{}); bus.emit('xxx', data);

适用场景:非父子组件通信(如Vue2无Pinia时),但需注意避免内存泄漏(组件卸载前off事件)。

4. webpack 与 Vite 的区别(核心差异)

维度webpackVite
构建原理基于「打包」:先递归解析所有模块,打包成bundle后再启动服务基于「原生ES模块(ESM)」:开发时不打包,直接按需加载模块,生产环境用Rollup打包
热更新(HMR)需重新打包更新的模块,大型项目热更新较慢只更新修改的模块,无需整体打包,热更新速度极快(毫秒级)
适用场景复杂项目(多入口、复杂依赖、需大量插件定制)、兼容旧浏览器现代前端项目(Vue/React/VitePress等)、追求开发效率、无需兼容IE
启动速度随项目体积增大变慢启动速度快(不依赖打包)
插件生态生态成熟(插件数量多)生态快速发展,兼容部分webpack插件(需适配器)

5. 如何进行 Axios 配置(项目实战版)

核心是「基础配置+拦截器+封装复用」,示例:

javascript
// 1. 基础配置(创建实例)
import axios from 'axios';
const service = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL, // 环境变量区分开发/生产
  timeout: 5000, // 请求超时
  headers: { 'Content-Type': 'application/json' }
});

// 2. 请求拦截器(添加Token、统一参数)
service.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token');
    if (token) config.headers.Authorization = `Bearer ${token}`;
    return config;
  },
  error => Promise.reject(error)
);

// 3. 响应拦截器(统一错误处理、数据解构)
service.interceptors.response.use(
  response => response.data, // 直接返回响应体,简化组件使用
  error => {
    // 统一错误提示(如401token过期、500服务器错误)
    if (error.response?.status === 401) {
      localStorage.removeItem('token');
      window.location.href = '/login';
    }
    ElMessage.error(error.message || '请求失败');
    return Promise.reject(error);
  }
);

// 4. 封装请求方法(GET/POST)
export const get = (url, params) => service.get(url, { params });
export const post = (url, data) => service.post(url, data);

扩展:可添加取消请求、请求重试、缓存请求结果等功能。

6. 节流处理(事件监听场景)

核心逻辑:规定时间内只执行一次函数,避免高频事件(滚动、 resize、输入框搜索)触发过多请求/计算。

javascript
// 通用节流函数(立即执行版)
function throttle(fn, delay = 500) {
  let lastTime = 0; // 上一次执行时间
  return function(...args) {
    const now = Date.now();
    if (now - lastTime >= delay) { // 间隔超过delay才执行
      fn.apply(this, args);
      lastTime = now;
    }
  };
}

// 项目使用(如滚动加载)
window.addEventListener('scroll', throttle(() => {
  console.log('滚动触发(500ms一次)');
  // 加载更多逻辑...
}, 500));

适用场景:滚动加载、按钮防重复点击(短时间内)、resize事件处理。

7. 防抖的设置

核心逻辑:触发事件后延迟n秒执行,若n秒内再次触发则重新计时,避免高频事件重复执行。

javascript
// 通用防抖函数(延迟执行版)
function debounce(fn, delay = 500, immediate = false) {
  let timer = null;
  return function(...args) {
    if (timer) clearTimeout(timer); // 重新触发时清除之前的定时器
    if (immediate && !timer) { // 立即执行版(首次触发直接执行)
      fn.apply(this, args);
    }
    timer = setTimeout(() => {
      fn.apply(this, args);
      timer = null;
    }, delay);
  };
}

// 项目使用(如搜索框输入联想)
const searchInput = document.querySelector('input');
searchInput.addEventListener('input', debounce((e) => {
  console.log('搜索请求:', e.target.value);
  // 发送搜索接口...
}, 300));

参数说明:immediate: true 适用于按钮提交(避免重复点击且立即响应),false 适用于输入框、搜索联想。

8. Tailwindcss 和普通 CSS 的优缺点

维度Tailwindcss普通CSS(含SCSS/LESS)
优点1. 原子化类,开发快速(无需写自定义类);2. 样式统一,减少命名冲突;3. 支持响应式、主题配置(无需写媒体查询);4. 生产环境自动 purge 无用样式,体积小1. 结构清晰(自定义类名语义化);2. 灵活度高(复杂样式易实现);3. 学习成本低(原生语法);4. 适合复杂组件样式复用(如BEM命名)
缺点1. 类名冗长(如 flex justify-center items-center);2. 学习成本(需记原子类);3. 复杂样式需自定义工具类,不如普通CSS直观1. 开发效率低(重复写样式);2. 易产生冗余样式;3. 响应式需写大量媒体查询;4. 多人协作易出现命名冲突
适用场景快速开发、响应式项目、组件库开发(如UI组件)复杂设计稿、需高度自定义样式的项目、团队熟悉原生CSS

9. 项目中如何进行 Pinia 状态管理

核心是「模块化划分+状态操作规范化」,步骤如下:

  1. 安装配置npm install pinia,在入口文件(如main.js)创建Pinia实例并挂载:
    javascript
    import { createPinia } from 'pinia';
    app.use(createPinia());
  2. 定义模块(Store):按业务划分(如user、cart、setting),示例:
    javascript
    // src/stores/user.js
    import { defineStore } from 'pinia';
    export const useUserStore = defineStore('user', {
      state: () => ({ // 状态
        token: localStorage.getItem('token') || '',
        userInfo: {}
      }),
      getters: { // 计算属性(缓存)
        isLogin: (state) => !!state.token
      },
      actions: { // 异步/同步操作(修改状态)
        setToken(newToken) {
          this.token = newToken;
          localStorage.setItem('token', newToken); // 持久化
        },
        async fetchUserInfo() { // 异步请求
          const res = await get('/api/user/info');
          this.userInfo = res.data;
        }
      }
    });
  3. 组件中使用
    javascript
    import { useUserStore } from '@/stores/user';
    const userStore = useUserStore();
    // 读取状态
    console.log(userStore.token);
    // 修改状态(直接修改/使用$patch批量修改)
    userStore.setToken('xxx');
    userStore.$patch({ userInfo: { name: 'xxx' } });
    // 异步操作
    userStore.fetchUserInfo();
  4. 持久化:简单场景用localStorage/sessionStorage(如上述示例),复杂场景用pinia-plugin-persistedstate插件。

10. localStorage 相关(特性+使用场景+注意事项)

  • 核心特性
    • 存储容量:约5MB;
    • 持久化:关闭浏览器后数据不丢失(需手动清除);
    • 同源限制:同一协议、域名、端口下可访问;
    • 仅存字符串:需用JSON.stringify()/JSON.parse()处理对象/数组。
  • 使用场景:存储不敏感的持久化数据(如用户token、主题配置、浏览历史)。
  • 注意事项
    • 不能存储敏感数据(如密码,易被XSS攻击窃取);
    • 存储大量数据会影响页面加载速度;
    • 跨域无法访问,需跨域共享数据可使用postMessage+localStorage或后端接口。

11. 主题切换该如何实现

核心是「CSS变量+状态管理+持久化」,步骤如下:

  1. 定义主题变量:在全局CSS中定义不同主题的变量(如light/dark):
    css
    /* src/assets/css/theme.css */
    :root { /* 默认light主题 */
      --bg-color: #fff;
      --text-color: #333;
      --primary-color: #42b983;
    }
    .theme-dark { /* dark主题 */
      --bg-color: #121212;
      --text-color: #eee;
      --primary-color: #66bb6a;
    }
  2. 在Pinia中管理主题状态
    javascript
    // src/stores/setting.js
    export const useSettingStore = defineStore('setting', {
      state: () => ({
        theme: localStorage.getItem('theme') || 'light' // 持久化
      }),
      actions: {
        toggleTheme() {
          this.theme = this.theme === 'light' ? 'dark' : 'light';
          localStorage.setItem('theme', this.theme);
          this.applyTheme(); // 应用主题
        },
        applyTheme() { // 初始化时应用主题
          document.documentElement.className = this.theme === 'dark' ? 'theme-dark' : '';
        }
      }
    });
  3. 组件中使用
    • 样式中使用CSS变量:body { background: var(--bg-color); color: var(--text-color); }
    • 切换主题:调用settingStore.toggleTheme()
  4. 扩展:复杂主题(如多配色)可通过动态加载CSS文件实现。

12. 如何确定当前播放的视频是哪一个

核心是「标识唯一性+状态跟踪」,常用方案:

  1. 给视频元素绑定唯一ID
    • 每个视频项分配唯一标识(如后端返回的videoId);
    • 用Pinia/全局变量存储当前播放的videoId,示例:
      javascript
      // 视频列表渲染
      <video 
        v-for="video in videoList" 
        :key="video.id"
        :data-id="video.id"
        @play="handlePlay(video.id)"
      ></video>
      // 记录当前播放视频ID
      const currentVideoId = ref('');
      const handlePlay = (videoId) => {
        currentVideoId.value = videoId; // 存储当前播放ID
        // 暂停其他视频(可选)
        document.querySelectorAll('video').forEach(v => {
          if (v.dataset.id !== videoId) v.pause();
        });
      };
  2. 基于DOM元素跟踪:通过document.activeElement判断是否为视频元素,或用querySelector('video:playing')(需结合CSS伪类)。
  3. 框架场景(如Vue):用v-model或组件通信传递当前播放状态,避免直接操作DOM。

13. 视频浏览记录历史保存(含播放进度)

实现方案:「本地存储+接口同步」,步骤如下:

  1. 存储结构设计:每条记录包含视频ID、标题、封面、播放进度、播放时间,示例:
    javascript
    // 单条记录格式
    {
      videoId: '123',
      title: 'xxx',
      cover: 'xxx.jpg',
      progress: 30, // 播放进度(秒)
      lastPlayTime: '2024-05-20 10:30'
    }
  2. 本地存储(优先)
    • 用localStorage存储浏览记录(最多保留N条,超出则删除最早的);
    • 视频播放时,每3秒或暂停时更新进度:
      javascript
      // 视频播放事件
      const video = document.querySelector('video');
      video.ontimeupdate = throttle(() => {
        const currentProgress = video.currentTime;
        // 更新本地存储中的进度
        updateHistoryProgress(videoId, currentProgress);
      }, 3000); // 节流,避免频繁存储
      video.onpause = () => {
        updateHistoryProgress(videoId, video.currentTime); // 暂停时强制更新
      };
  3. 接口同步(可选):用户登录后,将本地记录同步到后端,实现多设备同步;未登录时仅存储在本地。
  4. 返回视频时恢复进度:加载视频时,查询本地/后端的历史进度,设置video.currentTime = progress

14. CI/CD 部署流程(前端项目示例)

以「GitHub Actions + 阿里云服务器」为例,核心流程:

  1. 代码管理:代码托管在GitHub,按分支规范开发(dev开发、main生产)。
  2. CI(持续集成)
    • 触发条件:提交代码到dev/main分支时自动触发;
    • 执行步骤:
      1. 拉取代码;
      2. 安装依赖(npm install);
      3. 代码检查(ESLint);
      4. 构建项目(npm run build);
      5. 生成构建产物(dist目录)。
  3. CD(持续部署)
    • 开发环境(dev分支):构建成功后,通过SSH将dist目录上传到测试服务器,自动部署;
    • 生产环境(main分支):构建成功后,手动确认部署(或自动部署),上传到生产服务器,替换旧版本。
  4. 配置示例(GitHub Actions)
    yaml
    # .github/workflows/deploy.yml
    name: Deploy
    on:
      push:
        branches: [dev, main]
    jobs:
      build-and-deploy:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - name: Set up Node.js
            uses: actions/setup-node@v4
            with:
              node-version: '18'
          - name: Install dependencies
            run: npm install
          - name: Build
            run: npm run build
          - name: Deploy to server
            uses: easingthemes/ssh-deploy@main
            env:
              SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} # 服务器私钥(GitHub Secrets存储)
              ARGS: "-rltgoDzvO --delete"
              SOURCE: "dist/" # 构建产物目录
              REMOTE_HOST: ${{ secrets.REMOTE_HOST }} # 服务器IP
              REMOTE_USER: ${{ secrets.REMOTE_USER }} # 服务器用户名
              TARGET: "/var/www/xxx" # 服务器部署目录
  5. 扩展:可集成自动化测试(Jest、Cypress),测试通过后再部署。

15. provide 与 inject 使用场景

  • 核心作用:Vue中跨层级组件通信(父组件向子孙组件传递数据/方法,无需逐层props传递)。
  • 使用方式
    javascript
    // 父组件(provide提供数据)
    import { provide } from 'vue';
    provide('theme', 'dark'); // 第一个参数是key,第二个是值(可传对象、方法)
    provide('changeTheme', (newTheme) => { /* 方法 */ });
    
    // 子孙组件(inject接收数据)
    import { inject } from 'vue';
    const theme = inject('theme', 'light'); // 第二个参数是默认值
    const changeTheme = inject('changeTheme');
  • 项目应用场景
    • 全局配置(如主题、语言、权限);
    • 组件库开发(如ElMessageBox、ElNotification,通过provide/inject传递全局配置);
  • 注意事项
    • 数据是响应式的(若传递的是响应式对象/refs);
    • 避免滥用,跨层级通信优先用Pinia,provide/inject适合简单场景。

16. 移动端优先的设计理念

  • 核心定义:先设计移动端界面(小屏幕),再基于大屏设备(平板、PC)进行适配扩展,而非反过来。
  • 实现方式
    • 响应式布局:用媒体查询(@media (min-width: 768px))适配大屏;
    • 弹性布局:flex/grid布局,适应不同屏幕宽度;
    • 相对单位:用rem/vw/vh(如1rem=100px,通过html字体大小适配),避免固定px;
    • 触控友好:按钮尺寸≥44px×44px,间距合理,避免密集操作。
  • 优势
    • 适配更精准,避免大屏适配后移动端体验差;
    • 聚焦核心功能(移动端屏幕有限,优先保留核心功能);
    • 符合移动设备使用场景增长趋势。

17. 4K大屏仅输出1080p,如何避免缩放失真

  • 核心思路:让页面按「物理像素」渲染,避免浏览器自动缩放。
  • 实现方案
    1. 设置meta标签:确保viewport不缩放,适配设备宽度:
      html
      <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    2. 使用相对单位:用vw/vh(1vw=屏幕宽度的1%)或rem,基于屏幕宽度动态计算元素尺寸,而非固定px。
    3. 图片/资源适配:使用高分辨率图片(如2x图),通过image-set自动选择适配图片:
      css
      .img {
        background-image: image-set(
          url('img-1080p.jpg') 1x,
          url('img-4k.jpg') 2x
        );
      }
    4. CSS媒体查询适配:针对4K屏幕(如min-width: 3840px)单独优化布局,避免元素被过度拉伸。
    5. 框架层面适配:如Vue项目可使用postcss-px-to-viewport插件,自动将px转换为vw。

二、项目业务类问题(结合业务场景+技术选型原因)

1. 一刻短剧“滑动5个就重新刷新”的设计原因

核心是「性能优化+用户体验+业务需求」:

  • 性能优化:避免一次性加载过多视频(每个视频含视频文件、封面、文案),导致内存占用过高、页面卡顿,滑动5个刷新可分批加载,降低首屏加载压力。
  • 用户体验:用户连续滑动5个后,大概率需要新内容,提前刷新可避免后续滑动时出现“空白加载”,保证流畅性。
  • 业务需求:短剧内容多为连载/批量更新,分批刷新可优先展示最新/热门内容,同时减少接口请求频率(批量请求5个 vs 每次滑动请求1个)。
  • 扩展:可结合“预加载”(滑动到第3个时就请求下一批),进一步提升体验。

2. 抖音视频“提前加载、预处理”,点赞收藏“写死”的设计逻辑

  • 提前加载+预处理
    • 原因:视频播放需低延迟,提前加载(如用户当前播放第1个时,预加载第2、3个)可避免播放时缓冲;
    • 预处理:对视频进行转码(适配不同网络/设备)、压缩(减少文件大小)、缓存(本地存储近期播放的视频),提升加载速度。
  • 点赞收藏“写死”(实际是本地缓存+异步同步)
    • 设计逻辑:用户点击点赞/收藏时,先本地更新状态(如点赞按钮立即变红),再异步调用接口同步到后端;
    • 优势:避免接口请求延迟导致的“点击后无反应”,提升交互流畅性;即使网络波动,本地状态也能保持,后续网络恢复后自动同步。

3. 一刻短剧的性能优化方案(前端层面)

  • 资源优化
    • 视频优化:转码为HLS格式(支持分片加载)、根据网络状况切换清晰度(4G加载720p,WiFi加载1080p);
    • 图片优化:封面图使用WebP格式(压缩比高)、懒加载(loading="lazy")、缩略图预览。
  • 渲染优化
    • 列表虚拟化:使用vue-virtual-scroller等插件,只渲染可视区域内的视频项,避免大量DOM节点导致卡顿;
    • 减少重绘重排:视频容器尺寸固定,避免滑动时DOM结构变化;使用CSS3硬件加速(transform: translateZ(0))。
  • 接口优化
    • 批量请求:滑动时批量请求视频列表,减少接口调用次数;
    • 缓存策略:本地缓存已请求的视频列表、用户操作(点赞/收藏),避免重复请求;
    • 接口防抖:搜索、筛选时添加防抖,避免高频请求。
  • 其他优化
    • 懒加载非核心组件:如评论区、分享功能,滑动到对应区域再加载;
    • 内存释放:用户离开视频页面时,销毁视频实例、清除定时器,避免内存泄漏。

三、个人求职类问题(真诚+贴合岗位+展现适配性)

1. 有了解过我们公司吗?

参考回答: “了解过。贵公司是[行业领域,如“国内领先的短剧平台”/“专注于前端工程化解决方案的科技公司”],核心业务包括[具体业务,如“一刻短剧APP的开发与运营”/“企业级前端框架定制”],之前关注到贵公司推出的[产品/技术,如“XX短剧系列”/“XX前端组件库”]在行业内口碑很好,技术栈上以[前端技术,如Vue、Vite、Pinia]为主,和我目前的技术方向非常契合。另外,贵公司在[团队文化/行业地位,如“重视技术创新”/“快速发展的创业氛围”]方面的特点,也是我非常认可的,所以很希望能加入团队。”

2. 偏向的公司类型?

参考回答: “我更偏向「技术驱动+重视成长」的公司。一方面,希望公司有清晰的技术栈和工程化规范,能让我在实际项目中积累更专业的开发经验;另一方面,希望团队有良好的技术分享氛围,能和优秀的同事一起交流学习,不断提升自己的技术能力。贵公司的[业务/技术方向]正好符合我的期待,无论是项目复杂度还是技术迭代速度,都能让我快速成长。”

3. 直属上级和你在代码上有意见分歧,你该如何解决?

参考回答: “首先,我会先认真倾听上级的想法,了解他的核心诉求和考虑角度(比如性能、可维护性、业务兼容性),避免因为信息偏差导致分歧。然后,我会客观陈述自己的思路,比如代码的设计逻辑、技术选型的原因、可能带来的优势(如开发效率、后续扩展性),并拿出具体的示例或数据支持(如性能测试结果、类似项目案例)。如果还是无法达成共识,我会建议先小范围验证两种方案的可行性(比如写demo测试),基于实际效果做决策,而不是固执己见。最终的目标是保证代码质量和业务目标的实现,所以我会以理性、开放的态度沟通,尊重团队的最终决定。”

4. 你喜欢什么样的工作环境?

参考回答: “我喜欢「开放协作+高效务实」的工作环境。第一,团队内部沟通顺畅,遇到问题可以随时和同事、上级交流,没有层级壁垒;第二,大家都以结果为导向,注重效率,不搞形式主义;第三,有学习和成长的空间,比如定期的技术分享、项目复盘,能让我不断积累经验。另外,我也很看重工作和生活的平衡,这样才能保持持续的工作热情。”

5. 对实习的期待或者希望学习到什么?

参考回答: “首先,希望能深入参与实际项目的开发,将学校学到的理论知识转化为实操能力,尤其是在[前端技术方向,如Vue框架深入、工程化实践、性能优化]方面,积累真实项目的经验;其次,希望能学习到公司的开发规范和流程,比如代码评审、CI/CD部署、团队协作模式,培养专业的开发习惯;最后,希望能在前辈的指导下,提升解决问题的能力,比如遇到技术难题时的排查思路、业务需求的理解和转化能力。同时,我也会积极贡献自己的力量,认真完成分配的任务,为团队创造价值。”

6. 个人投递方向全是前端吗?

参考回答: “是的,我一直专注于前端开发方向。从学习阶段开始,我就系统学习了HTML、CSS、JavaScript、Vue等核心技术,也做过[个人项目/课程项目,如“博客系统”/“短视频播放器”]等前端相关项目,积累了一定的实操经验。我对前端开发的兴趣很浓厚,尤其是在用户交互体验、工程化优化方面,希望能一直深耕这个领域,所以投递的全部是前端相关岗位。”

7. 什么时间入职?

参考回答: “我目前是[学生身份,如“大三学生”],课程安排比较灵活,只要拿到offer,我可以在[具体时间,如“1-2周内”/“暑假期间”]入职,并且能保证[实习时长,如“3个月以上”]的全职实习时间,期间会合理协调学业和工作,确保不影响实习任务的完成。”

8. 实习多久?

参考回答: “我计划实习[3-6个月],如果期间双方合作愉快,并且学校课程允许,我也非常愿意延长实习时间。我希望能有足够的时间深入参与项目,不仅完成基础任务,还能在后续的工作中承担更多责任,真正学到东西,同时也为团队带来持续的价值。”

9. 平时开发有使用什么好用的AI吗?

参考回答: “我常用的AI工具主要是辅助开发效率的,比如:

  • GitHub Copilot:写代码时提供自动补全、语法提示,尤其是复杂逻辑或不熟悉的API,能节省查文档的时间;
  • ChatGPT:遇到技术难题(如bug排查、语法疑问)时,会用来辅助分析思路,但不会直接复制代码,而是理解后结合自己的需求修改;
  • CodeLlama:偶尔用来优化代码结构、生成单元测试;
  • Figma AI:如果涉及简单的UI设计(如项目原型),会用它辅助生成设计稿,提升协作效率。 我认为AI是很好的辅助工具,但核心还是自己的技术能力,所以会合理利用AI提升效率,同时注重理解底层逻辑,避免过度依赖。”

分割线

如果需要针对某个问题的答案进行细化(如补充具体项目案例、调整表达风格),或者想模拟面试场景进行问答演练,欢迎告诉我,我可以帮你进一步优化!

4复盘反思

首先,不要眼睛到处看,不要乱动身体,不要摇头晃脑,看着很不礼貌,端坐看着屏幕。本次的面试说是技术面是最后一次,也就是我的全部面试都已经结束了,我个人感觉很有希望啊!😋😋😋

>11/27/25 不是,都一整天了,怎么还不给我发offer啊?我还不够格吗?