JS面试官必备:10道考察前端技术实力的面试题
2024-02-04 06:35:23
10 个 JavaScript 面试题,助你征服前端工程师面试
作为前端开发中的主力军,JavaScript 在企业招聘中备受重视,面试官也视其为考察技术人员能力的利器。无论是作为面试者还是面试官,掌握以下 10 个 JavaScript 面试题,都能帮助你在面试中脱颖而出,快速寻觅到合适的岗位。
1. 揭秘 JavaScript 中的继承之道
问题: 如何在 JavaScript 中实现继承?
答案: JavaScript 提供了两种继承方式:原型继承和类继承。
- 原型继承: 通过创建新对象的原型指向原有对象的原型,实现继承。
const parent = {
name: 'Parent',
};
const child = Object.create(parent);
child.name = 'Child';
console.log(child.name); // Output: "Child"
- 类继承: 使用
class
实现继承,更接近传统面向对象编程的继承概念。
class Parent {
constructor(name) {
this.name = name;
}
}
class Child extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
}
const child = new Child('Child', 10);
console.log(child.name, child.age); // Output: "Child" 10
2. 巧用事件委托,高效处理事件
问题: 如何在 JavaScript 中实现事件委托?
答案: 事件委托是一种在 HTML 文档中处理事件的有效方法。通过将事件处理程序附加到文档中的某个元素上,当该元素或其子元素发生事件时,都可以由该事件处理程序处理。
<div id="parent">
<button id="child">Click me</button>
</div>
<script>
const parent = document.getElementById('parent');
parent.addEventListener('click', (event) => {
// 处理点击事件,无论目标元素是 parent 还是 child
console.log('Click event handled!');
});
</script>
3. 探索闭包的奥秘,掌控变量作用域
问题: 如何在 JavaScript 中使用闭包?
答案: 闭包是指能够访问外部函数作用域中变量的函数。闭包可以实现私有变量、函数柯里化和惰性求值等功能。
function createCounter() {
let count = 0; // 私有变量
return function () {
return count++;
};
}
const counter = createCounter();
console.log(counter()); // Output: 0
console.log(counter()); // Output: 1
4. 掌握异步编程,驾驭非阻塞之道
问题: 如何在 JavaScript 中实现异步编程?
答案: 异步编程允许 JavaScript 代码在不阻塞主线程的情况下执行。可以通过 Promise
、async/await
和回调函数等方式实现异步编程。
// 使用 Promise 实现异步
fetch('data.json')
.then((response) => response.json())
.then((data) => {
// 处理数据
});
// 使用 async/await 实现异步
async function getData() {
const response = await fetch('data.json');
const data = await response.json();
return data;
}
5. 深入理解对象深拷贝,避免浅表复制的陷阱
问题: 如何在 JavaScript 中实现对象深拷贝?
答案: 对象深拷贝是指创建一个新对象,并且将原对象的所有属性和值复制到新对象中,包括嵌套的对象和数组。可以通过递归、JSON.parse(JSON.stringify(obj))
或 Object.assign()
方法实现对象深拷贝。
// 使用递归实现深拷贝
function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) return obj;
if (Array.isArray(obj)) {
return obj.map(deepCopy);
} else {
const newObj = {};
for (const key in obj) {
newObj[key] = deepCopy(obj[key]);
}
return newObj;
}
}
// 使用 JSON.parse(JSON.stringify(obj)) 实现深拷贝
const deepCopy = JSON.parse(JSON.stringify(obj));
// 使用 Object.assign() 实现深拷贝(不适用于嵌套对象)
const deepCopy = Object.assign({}, obj);
6. 驾轻就熟,巧用数组去重化繁为简
问题: 如何在 JavaScript 中实现数组去重?
答案: 数组去重是指从数组中移除重复的元素,只保留唯一的元素。可以通过 Set()
、filter()
方法或 reduce()
方法实现数组去重。
// 使用 Set() 实现数组去重
const uniqueArray = [...new Set(arr)];
// 使用 filter() 方法实现数组去重
const uniqueArray = arr.filter((item, index) => arr.indexOf(item) === index);
// 使用 reduce() 方法实现数组去重
const uniqueArray = arr.reduce((acc, item) => acc.includes(item) ? acc : [...acc, item], []);
7. 函数柯里化:拆分参数,提升代码复用性
问题: 如何在 JavaScript 中实现函数柯里化?
答案: 函数柯里化是指将一个函数的部分参数固定下来,然后返回一个新的函数,该函数接受剩余的参数。可以通过闭包或 bind()
方法实现函数柯里化。
// 使用闭包实现函数柯里化
const add = (a) => (b) => a + b;
const add5 = add(5);
console.log(add5(10)); // Output: 15
// 使用 bind() 方法实现函数柯里化
const add = function (a, b) {
return a + b;
};
const add5 = add.bind(null, 5);
console.log(add5(10)); // Output: 15
8. 探索惰性求值:按需计算,优化性能
问题: 如何在 JavaScript 中实现惰性求值?
答案: 惰性求值是指只有在需要的时候才计算表达式的值。可以通过闭包或 memoize()
函数实现惰性求值。
// 使用闭包实现惰性求值
function createCounter() {
let count = 0;
return function () {
return count++;
};
}
const counter = createCounter();
console.log(counter()); // Output: 0
console.log(counter()); // Output: 1
// 使用 memoize() 函数实现惰性求值
const memoize = (fn) => {
const cache = {};
return (...args) => {
const key = JSON.stringify(args);
if (key in cache) return cache[key];
const result = fn(...args);
cache[key] = result;
return result;
};
};
const fibonacci = (n) => {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
};
const memoizedFibonacci = memoize(fibonacci);
console.log(memoizedFibonacci(10)); // Output: 55
9. 节流和防抖:控制函数执行,避免过度触发
问题: 如何在 JavaScript 中实现节流和防抖?
答案: 节流和防抖都是用来控制函数的执行频率的技术。节流是指在一定时间间隔内只执行一次函数,而防抖是指只有在函数停止执行一段时间后才执行一次函数。可以通过 setTimeout()
和 clearTimeout()
方法实现节流和防抖。
// 使用节流实现
function throttle(fn, delay) {
let lastCall = 0;
return (...args) => {
const now = Date.now();
if (now - lastCall < delay) return;
lastCall = now;
fn(...args);
};
}
// 使用防抖实现
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
fn(...args);
}, delay);
};
}
10. 代理模式:灵活扩展,解耦对象
问题: 如何在 JavaScript 中实现代理模式?
答案: 代理模式是一种设计模式,它允许你在不改变原有对象的情况下,为该对象添加新的功能。可以通过使用 Proxy()
对象实现代理模式。
// 使用 Proxy() 实现代理模式
const target = {
name: '