返回

JS面试官必备:10道考察前端技术实力的面试题

前端

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 代码在不阻塞主线程的情况下执行。可以通过 Promiseasync/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: '