返回
前端手撕高频面试题——拿下高薪Offer
前端
2023-11-13 20:57:43
在前端开发的求职面试中,“手撕”前端的考题可以说是各位面试官最钟爱的环节了。而针对这方面的针对性训练,对各位求职者而言也是至关重要的。
为此,本文将对面试中高频出现的“手写”题目进行梳理,给出思路和参考的示例解答,供大家参考。
一、判断属性值相等
题目:
const obj1 = { a: 1, b: 2 };
const obj2 = { a: 1, b: 2 };
const obj3 = { a: '1', b: '2' };
console.log(obj1.a === obj2.a); // true
console.log(obj1.a === obj3.a); // false
解析:
- === 操作符对左右两边的值都会先进行全等转换,再进行严格相等判断;
- 严格相等判断会区分数据值的属性,即数值型与字符串型视为不等。
二、数组扁平化
题目:
const arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
console.log(arr.reduce((acc, cur) => acc.join(',') + cur.join(','), ')); // 1,2,3,4,5,6,7,8,9
解析:
- 利用 reduce() 方法依次遍历数组;
- 将每个嵌套数组 join 成字符串;
- 再将这些字符串片段逐次拼接起来即可达到扁平化。
三、深拷贝
题目:
const obj1 = { a: [1, 2, 3] };
const obj2 = deepCopy(obj1);
obj2.a[0] = 0;
console.log(obj1.a[0]); // 0
解析:
- 利用递归遍历对象的每一层级,既可以复制复杂嵌套的对象。
- 遍历到最底层时,直接进行值的拷贝。
- 遍历到嵌套结构,则进行递归调用。
四、数组去重
题目:
const arr = [1, 2, 3, 2, 4, 5, 6, 5, 3];
console.log([...new Set(arr)]); // [1, 2, 3, 4, 5, 6]
解析:
- 利用 Set 数据结构的特性,自动去重;
- 再将 Set 转换为 Array 输出。
五、防抖节流
题目:
function debounce(fn, delay) {
let lastTime = 0;
return (...args) => {
if (Date.now() - lastTime < delay) {
return;
}
lastTime = Date.now();
return fn(...args);
};
}
解析:
- 闭包中定义一个 lastTime 变量,用于计时;
- 判断时间间隔大于 delay,则触发防抖;
- 通过重复触发该方法,可达到防抖的效果。
六、节流
题目:
function throttle(fn, delay) {
let flag = false;
return (...args) => {
if (flag) {
return;
}
flag = true;
window.requestAnimationFrame(() => {
flag = false;
fn(...args);
});
};
}
解析:
- 闭包中定义一个 flag 变量,用于判断节流;
- 通过 requestAnimationFrame 优化,保证在帧动画的第一次回调中再调用原方法。
七、继承
题目:
class Base {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
class Child extends Base {
constructor(age) {
super('demo');
this.age = age;
}
getAge() {
return this.age;
}
}
const child = new Child(18);
console.log(child.getName()); // demo
console.log(child.getAge()); // 18
解析:
- 子类在构造方法中 super 调用父类构造方法;
- super(...) 传入的参数应和父类构造器相匹配。
八、手写 Promise
题目:
class Promise {
constructor(callback) {
this.callback = callbacks;
}
then(success) {
this.successCallback = success;
this.executeCallback();
}
catch(fail) {
this.failCallback = fail;
this.executeCallback();
}
executeCallback() {
try {
const res = this.callback();
if (res) {
res.then(this.successCallback);
}
} catch (err) {
this.failCallback && this.failCallback(err);
}
}
}
解析:
- 利用类实现了 Promise 的简易版本;
- 通过 then() 与 catch() 方法,定义好不同的回调;
- 再使用一个通用的方法来调用这些回调。
九、Vue 生命周期的顺序
<script>
export default {
beforeCreate() { },
created() { },
beforeUpdate() { },
mounted() { },
activated() { },
beforeUnmount() { },
beforeDesotry() { },
unmounted() { },
desotryed() { }
};
</script>
解析:
- Vue 组件生命周期的顺序如下:
- 创建前:beforeCreate
- 已初始化:created
- 更新前:beforeUpdate
- 已装载:mounted
- 激活后:activated
- 卸载前:beforeUnmount
- 销毁前:beforeDesotry
- 已卸载:unmounted
- 已销毁:desotryed
- 根据组件的使用场景,选择性地使用这些钩子。
十、手写一个简易的 Vuex 仓库
class Store {
constructor() {
this.state = {};
this.actions = {};
this.mutations = {};
this.getters = {};
}
setState(newState) {
this.state = { ...this.state, ...newState };
}
getState() {
return this.state;
}
// 其余略
}
解析:
- 使用类来简化 Vuex 的基础架构;
- 暴露 state、actions、mutations、getters 等 API;
- 利用 setState() 方法来进行内部 state 管理。
以上便是前端面试中常见的高频手撕题目,希望能对大家有所帮助。切记,勤加训练,熟能生巧,才能在激烈的竞争中脱颖而出。