# 🚀 JavaScript面试必刷!50道核心概念+ES6+新特性详解

146 阅读7分钟

金九银十面试季,这些JavaScript题你都会吗?本文整理了50道高频面试题,涵盖核心概念和ES6+新特性,助你轻松通关前端面试!

其他面试链接

# 前端面试必刷!50道HTML+CSS高频面试题详解

📚 目录


🎯 JavaScript基础篇

1. JavaScript中的数据类型有哪些?

答案: JavaScript有8种数据类型:

  • 基本类型undefinednullbooleannumberstringsymbolbigint
  • 引用类型object

详解:

// 基本类型
let a = undefined;
let b = null;
let c = true;
let d = 42;
let e = "hello";
let f = Symbol('symbol');
let g = 123n; // BigInt

// 引用类型
let h = { name: 'John' };
let i = [1, 2, 3];
let j = function() {};

类型检测:

// typeof 操作符
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (这是JavaScript的一个bug)
console.log(typeof true); // "boolean"
console.log(typeof 42); // "number"
console.log(typeof "hello"); // "string"
console.log(typeof Symbol()); // "symbol"
console.log(typeof 123n); // "bigint"
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function(){}); // "function"

// instanceof 操作符
console.log([] instanceof Array); // true
console.log({} instanceof Object); // true
console.log(function(){} instanceof Function); // true

// Object.prototype.toString.call()
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call([])); // "[object Array]"

2. 什么是变量提升(Hoisting)?

答案: 变量提升是JavaScript引擎在执行代码前,将变量和函数声明提升到当前作用域顶部的过程。

详解:

// 变量提升
console.log(a); // undefined
var a = 10;

// 等价于:
var a;
console.log(a); // undefined
a = 10;

// 函数提升
foo(); // "Hello"
function foo() {
  console.log("Hello");
}

// let和const不会提升
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;

// 函数表达式不会提升
bar(); // TypeError: bar is not a function
var bar = function() {
  console.log("World");
};

实际应用:

// 避免变量提升带来的问题
function example() {
  // 将所有变量声明放在函数顶部
  var a, b, c;
  
  // 业务逻辑
  a = 1;
  b = 2;
  c = a + b;
  
  return c;
}

// 使用let/const避免提升
function modernExample() {
  const a = 1;
  const b = 2;
  const c = a + b;
  
  return c;
}

3. 什么是事件循环(Event Loop)?

答案: 事件循环是JavaScript处理异步操作的机制,通过任务队列和微任务队列来管理代码执行顺序。

详解:

console.log('1'); // 同步任务

setTimeout(() => {
  console.log('2'); // 宏任务
}, 0);

Promise.resolve().then(() => {
  console.log('3'); // 微任务
});

console.log('4'); // 同步任务

// 输出顺序:1, 4, 3, 2

执行顺序:

  1. 同步任务:立即执行
  2. 微任务:Promise.then、process.nextTick、MutationObserver
  3. 宏任务:setTimeout、setInterval、setImmediate、requestAnimationFrame

实际应用:

// 异步操作示例
function asyncExample() {
  console.log('开始');
  
  // 宏任务
  setTimeout(() => {
    console.log('宏任务1');
    
    // 微任务
    Promise.resolve().then(() => {
      console.log('微任务1');
    });
  }, 0);
  
  // 微任务
  Promise.resolve().then(() => {
    console.log('微任务2');
    
    // 宏任务
    setTimeout(() => {
      console.log('宏任务2');
    }, 0);
  });
  
  console.log('结束');
}

// 输出:开始, 结束, 微任务2, 宏任务1, 微任务1, 宏任务2

🔒 作用域与闭包篇

4. 什么是闭包(Closure)?

答案: 闭包是指有权访问另一个函数作用域中变量的函数,即使外部函数已经执行完毕。

详解:

function outer() {
  let count = 0;
  
  function inner() {
    count++;
    console.log(count);
  }
  
  return inner;
}

const counter = outer();
counter(); // 1
counter(); // 2
counter(); // 3

闭包的应用场景:

// 1. 数据私有化
function createCounter() {
  let count = 0;
  
  return {
    increment() {
      count++;
      return count;
    },
    decrement() {
      count--;
      return count;
    },
    getCount() {
      return count;
    }
  };
}

const counter = createCounter();
console.log(counter.getCount()); // 0
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1

// 2. 函数工厂
function multiply(x) {
  return function(y) {
    return x * y;
  };
}

const multiplyBy2 = multiply(2);
const multiplyBy3 = multiply(3);

console.log(multiplyBy2(4)); // 8
console.log(multiplyBy3(4)); // 12

// 3. 事件处理
function createButtonHandler(id) {
  return function() {
    console.log(`Button ${id} clicked`);
  };
}

const button1Handler = createButtonHandler(1);
const button2Handler = createButtonHandler(2);

5. 什么是作用域链(Scope Chain)?

答案: 作用域链是JavaScript引擎查找变量时遵循的规则,从当前作用域开始,逐级向上查找。

详解:

let globalVar = 'global';

function outer() {
  let outerVar = 'outer';
  
  function inner() {
    let innerVar = 'inner';
    
    console.log(innerVar); // 'inner' - 当前作用域
    console.log(outerVar); // 'outer' - 外层作用域
    console.log(globalVar); // 'global' - 全局作用域
  }
  
  inner();
}

outer();

作用域链查找过程:

// 变量查找示例
let x = 1;

function a() {
  let x = 2;
  
  function b() {
    let x = 3;
    
    function c() {
      console.log(x); // 3 - 找到最近的x
    }
    
    c();
  }
  
  b();
}

a(); // 输出:3

6. 什么是this关键字?

答案: this是JavaScript中的一个关键字,指向当前执行上下文的对象。

详解:

// 1. 全局上下文
console.log(this); // Window对象(浏览器)或global对象(Node.js)

// 2. 函数上下文
function normalFunction() {
  console.log(this);
}

normalFunction(); // Window对象(非严格模式)或undefined(严格模式)

// 3. 对象方法
const obj = {
  name: 'John',
  sayHello() {
    console.log(`Hello, ${this.name}`);
  }
};

obj.sayHello(); // "Hello, John"

// 4. 构造函数
function Person(name) {
  this.name = name;
}

const person = new Person('Alice');
console.log(person.name); // "Alice"

// 5. 箭头函数
const arrowObj = {
  name: 'Bob',
  sayHello: () => {
    console.log(`Hello, ${this.name}`);
  }
};

arrowObj.sayHello(); // "Hello, undefined" - 箭头函数没有自己的this

this绑定方式:

// 1. 默认绑定
function defaultBinding() {
  console.log(this);
}
defaultBinding(); // Window对象

// 2. 隐式绑定
const obj = {
  name: 'John',
  method() {
    console.log(this.name);
  }
};
obj.method(); // "John"

// 3. 显式绑定
function explicitBinding() {
  console.log(this.name);
}

const person = { name: 'Alice' };
explicitBinding.call(person); // "Alice"
explicitBinding.apply(person); // "Alice"
explicitBinding.bind(person)(); // "Alice"

// 4. new绑定
function NewBinding(name) {
  this.name = name;
}
const newObj = new NewBinding('Bob');
console.log(newObj.name); // "Bob"

🔗 原型与继承篇

7. 什么是原型链(Prototype Chain)?

答案: 原型链是JavaScript实现继承的机制,通过__proto__属性连接对象和其原型对象。

详解:

// 原型链示例
function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function() {
  console.log(`Hello, I'm ${this.name}`);
};

const person = new Person('John');
person.sayHello(); // "Hello, I'm John"

// 原型链查找过程
console.log(person.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true

原型链查找:

// 属性查找过程
const obj = {};

// 1. 查找obj自身属性
console.log(obj.hasOwnProperty('toString')); // false

// 2. 查找obj.__proto__(Object.prototype)
console.log(obj.__proto__.hasOwnProperty('toString')); // true

// 3. 最终找到toString方法
console.log(obj.toString()); // "[object Object]"

8. 如何实现继承?

答案: JavaScript有多种继承方式:原型链继承、构造函数继承、组合继承、寄生组合继承等。

详解:

// 1. 原型链继承
function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(`${this.name} makes a sound`);
};

function Dog(name) {
  this.name = name;
}

Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

const dog = new Dog('Buddy');
dog.speak(); // "Buddy makes a sound"

// 2. 构造函数继承
function Animal(name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}

function Dog(name) {
  Animal.call(this, name);
}

const dog1 = new Dog('Buddy');
const dog2 = new Dog('Max');

dog1.colors.push('yellow');
console.log(dog1.colors); // ['red', 'blue', 'green', 'yellow']
console.log(dog2.colors); // ['red', 'blue', 'green']

// 3. 组合继承
function Animal(name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}

Animal.prototype.speak = function() {
  console.log(`${this.name} makes a sound`);
};

function Dog(name) {
  Animal.call(this, name); // 继承属性
}

Dog.prototype = new Animal(); // 继承方法
Dog.prototype.constructor = Dog;

const dog = new Dog('Buddy');
dog.speak(); // "Buddy makes a sound"

// 4. 寄生组合继承(推荐)
function inheritPrototype(subType, superType) {
  const prototype = Object.create(superType.prototype);
  prototype.constructor = subType;
  subType.prototype = prototype;
}

function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(`${this.name} makes a sound`);
};

function Dog(name) {
  Animal.call(this, name);
}

inheritPrototype(Dog, Animal);

const dog = new Dog('Buddy');
dog.speak(); // "Buddy makes a sound"

9. ES6的class语法如何工作?

答案: ES6的class是语法糖,底层仍然基于原型链实现。

详解:

// ES6 class语法
class Animal {
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(`${this.name} makes a sound`);
  }
  
  static create(name) {
    return new Animal(name);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }
  
  speak() {
    console.log(`${this.name} barks`);
  }
}

const dog = new Dog('Buddy', 'Golden Retriever');
dog.speak(); // "Buddy barks"

// 等价的原型链写法
function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(`${this.name} makes a sound`);
};

Animal.create = function(name) {
  return new Animal(name);
};

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() {
  console.log(`${this.name} barks`);
};

⚡ 异步编程篇

10. 什么是Promise?

答案: Promise是JavaScript中处理异步操作的对象,代表一个可能还没有完成的操作的最终结果。

详解:

// Promise基本用法
const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    const random = Math.random();
    if (random > 0.5) {
      resolve('成功');
    } else {
      reject('失败');
    }
  }, 1000);
});

promise
  .then(result => {
    console.log('成功:', result);
  })
  .catch(error => {
    console.log('失败:', error);
  })
  .finally(() => {
    console.log('完成');
  });

Promise链式调用:

// 链式调用
function fetchUser(id) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ id, name: 'John' });
    }, 1000);
  });
}

function fetchUserPosts(userId) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve([{ id: 1, title: 'Post 1' }, { id: 2, title: 'Post 2' }]);
    }, 1000);
  });
}

fetchUser(1)
  .then(user => {
    console.log('用户信息:', user);
    return fetchUserPosts(user.id);
  })
  .then(posts => {
    console.log('用户文章:', posts);
  })
  .catch(error => {
    console.log('错误:', error);
  });

Promise静态方法:

// Promise.all - 所有Promise都成功
const promises = [
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3)
];

Promise.all(promises)
  .then(results => {
    console.log(results); // [1, 2, 3]
  });

// Promise.race - 第一个完成的Promise
Promise.race([
  new Promise(resolve => setTimeout(() => resolve('A'), 1000)),
  new Promise(resolve => setTimeout(() => resolve('B'), 500))
])
.then(result => {
  console.log(result); // "B"
});

// Promise.allSettled - 所有Promise都完成(无论成功失败)
Promise.allSettled([
  Promise.resolve(1),
  Promise.reject('error'),
  Promise.resolve(3)
])
.then(results => {
  console.log(results);
  // [
  //   { status: 'fulfilled', value: 1 },
  //   { status: 'rejected', reason: 'error' },
  //   { status: 'fulfilled', value: 3 }
  // ]
});

11. 什么是async/await?

答案: async/await是ES2017引入的语法糖,让异步代码看起来像同步代码。

详解:

// async/await基本用法
async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('获取数据失败:', error);
  }
}

// 等价于Promise写法
function fetchDataPromise() {
  return fetch('https://api.example.com/data')
    .then(response => response.json())
    .catch(error => {
      console.error('获取数据失败:', error);
    });
}

async/await错误处理:

// 错误处理方式
async function handleErrors() {
  try {
    const result = await riskyOperation();
    return result;
  } catch (error) {
    console.error('操作失败:', error);
    return null;
  }
}

// 或者使用.catch()
async function handleErrors2() {
  const result = await riskyOperation().catch(error => {
    console.error('操作失败:', error);
    return null;
  });
  return result;
}

并行执行:

// 串行执行
async function sequential() {
  const result1 = await fetch('https://api1.com');
  const result2 = await fetch('https://api2.com');
  return [result1, result2];
}

// 并行执行
async function parallel() {
  const [result1, result2] = await Promise.all([
    fetch('https://api1.com'),
    fetch('https://api2.com')
  ]);
  return [result1, result2];
}

🆕 ES6+新特性篇

12. 什么是箭头函数?

答案: 箭头函数是ES6引入的简洁函数语法,没有自己的this、arguments、super、new.target。

详解:

// 基本语法
const add = (a, b) => a + b;

// 等价于
function add(a, b) {
  return a + b;
}

// 多行函数体
const multiply = (a, b) => {
  const result = a * b;
  return result;
};

// 单个参数可以省略括号
const square = x => x * x;

// 无参数需要括号
const getRandom = () => Math.random();

this绑定:

// 传统函数
const obj = {
  name: 'John',
  traditionalMethod: function() {
    setTimeout(function() {
      console.log(this.name); // undefined
    }, 100);
  },
  
  arrowMethod: function() {
    setTimeout(() => {
      console.log(this.name); // "John"
    }, 100);
  }
};

obj.traditionalMethod();
obj.arrowMethod();

实际应用:

// 数组方法中使用
const numbers = [1, 2, 3, 4, 5];

const doubled = numbers.map(n => n * 2);
const filtered = numbers.filter(n => n > 2);
const sum = numbers.reduce((acc, n) => acc + n, 0);

console.log(doubled); // [2, 4, 6, 8, 10]
console.log(filtered); // [3, 4, 5]
console.log(sum); // 15

13. 什么是解构赋值?

答案: 解构赋值是ES6引入的语法,可以从数组或对象中提取值并赋给变量。

详解:

// 数组解构
const [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1, 2, 3

// 跳过元素
const [first, , third] = [1, 2, 3];
console.log(first, third); // 1, 3

// 默认值
const [x = 0, y = 0] = [1];
console.log(x, y); // 1, 0

// 剩余参数
const [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]

对象解构:

// 基本对象解构
const person = { name: 'John', age: 30, city: 'New York' };
const { name, age, city } = person;
console.log(name, age, city); // "John", 30, "New York"

// 重命名
const { name: userName, age: userAge } = person;
console.log(userName, userAge); // "John", 30

// 默认值
const { name, age, country = 'USA' } = person;
console.log(country); // "USA"

// 嵌套解构
const user = {
  id: 1,
  profile: {
    name: 'John',
    email: 'john@example.com'
  }
};

const { profile: { name, email } } = user;
console.log(name, email); // "John", "john@example.com"

实际应用:

// 函数参数解构
function printUser({ name, age, email = 'N/A' }) {
  console.log(`Name: ${name}, Age: ${age}, Email: ${email}`);
}

printUser({ name: 'John', age: 30 }); // "Name: John, Age: 30, Email: N/A"

// 交换变量
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2, 1

// 从函数返回多个值
function getCoordinates() {
  return [10, 20];
}

const [x, y] = getCoordinates();
console.log(x, y); // 10, 20

14. 什么是模板字符串?

答案: 模板字符串是ES6引入的字符串字面量语法,支持多行字符串和字符串插值。

详解:

// 基本语法
const name = 'John';
const age = 30;

const greeting = `Hello, my name is ${name} and I'm ${age} years old.`;
console.log(greeting); // "Hello, my name is John and I'm 30 years old."

// 多行字符串
const multiLine = `
  This is a
  multi-line
  string.
`;
console.log(multiLine);

// 表达式
const price = 10;
const quantity = 3;
const total = `Total: $${price * quantity}`;
console.log(total); // "Total: $30"

标签模板:

// 标签模板函数
function highlight(strings, ...values) {
  let result = '';
  strings.forEach((string, i) => {
    result += string;
    if (values[i]) {
      result += `<span class="highlight">${values[i]}</span>`;
    }
  });
  return result;
}

const name = 'John';
const age = 30;

const highlighted = highlight`Hello, my name is ${name} and I'm ${age} years old.`;
console.log(highlighted);
// "Hello, my name is <span class="highlight">John</span> and I'm <span class="highlight">30</span> years old."

15. 什么是let和const?

答案: let和const是ES6引入的块级作用域变量声明,let允许重新赋值,const不允许。

详解:

// let - 可以重新赋值
let count = 0;
count = 1; // 允许

// const - 不能重新赋值
const PI = 3.14159;
// PI = 3.14; // TypeError: Assignment to constant variable

// 块级作用域
{
  let blockVar = 'block scope';
  const blockConst = 'block constant';
}
// console.log(blockVar); // ReferenceError
// console.log(blockConst); // ReferenceError

// 暂时性死区
console.log(hoistedVar); // undefined
var hoistedVar = 'hoisted';

// console.log(tdzVar); // ReferenceError
let tdzVar = 'tdz';

const的特殊性:

// const只保证引用不变,不保证对象内容不变
const user = { name: 'John', age: 30 };

user.age = 31; // 允许
user.name = 'Jane'; // 允许

// user = { name: 'Bob' }; // TypeError

// 冻结对象
const frozenUser = Object.freeze({ name: 'John', age: 30 });
// frozenUser.age = 31; // 在严格模式下会报错

📦 模块化篇

16. ES6模块系统如何工作?

答案: ES6模块系统提供了静态的模块结构,支持导入和导出语法。

详解:

// 导出语法
// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;

// 默认导出
export default function divide(a, b) {
  return a / b;
}

// 导入语法
// main.js
import { add, subtract } from './math.js';
import divide from './math.js'; // 默认导入
import * as MathUtils from './math.js'; // 命名空间导入

console.log(add(5, 3)); // 8
console.log(divide(10, 2)); // 5
console.log(MathUtils.multiply(4, 5)); // 20

动态导入:

// 动态导入
async function loadModule() {
  try {
    const module = await import('./math.js');
    console.log(module.add(2, 3)); // 5
  } catch (error) {
    console.error('模块加载失败:', error);
  }
}

// 条件导入
if (condition) {
  import('./feature.js').then(module => {
    module.default();
  });
}

模块特性:

// 1. 严格模式
// 所有模块都在严格模式下运行

// 2. 静态结构
// 导入导出必须在顶层,不能在条件语句中

// 3. 单例模式
// 模块只加载一次,多次导入返回同一个实例

// 4. 循环依赖处理
// a.js
import { b } from './b.js';
export const a = 'a';

// b.js
import { a } from './a.js';
export const b = 'b';

⚡ 性能优化篇

17. 如何优化JavaScript性能?

答案: 通过减少DOM操作、使用事件委托、避免内存泄漏、代码分割等方法优化性能。

详解:

// 1. 减少DOM操作
// 不好的做法
for (let i = 0; i < 1000; i++) {
  const div = document.createElement('div');
  document.body.appendChild(div);
}

// 好的做法
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
  const div = document.createElement('div');
  fragment.appendChild(div);
}
document.body.appendChild(fragment);

// 2. 事件委托
// 不好的做法
const buttons = document.querySelectorAll('button');
buttons.forEach(button => {
  button.addEventListener('click', handleClick);
});

// 好的做法
document.addEventListener('click', (event) => {
  if (event.target.matches('button')) {
    handleClick(event);
  }
});

// 3. 防抖和节流
function debounce(func, wait) {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
}

function throttle(func, limit) {
  let inThrottle;
  return function() {
    const args = arguments;
    const context = this;
    if (!inThrottle) {
      func.apply(context, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

// 使用示例
const debouncedSearch = debounce(searchAPI, 300);
const throttledScroll = throttle(handleScroll, 100);

内存管理:

// 避免内存泄漏
class EventHandler {
  constructor() {
    this.element = document.getElementById('myElement');
    this.handleClick = this.handleClick.bind(this);
    this.element.addEventListener('click', this.handleClick);
  }
  
  handleClick() {
    console.log('Clicked');
  }
  
  destroy() {
    this.element.removeEventListener('click', this.handleClick);
    this.element = null;
  }
}

// 使用WeakMap避免循环引用
const cache = new WeakMap();

function expensiveOperation(obj) {
  if (cache.has(obj)) {
    return cache.get(obj);
  }
  
  const result = /* 复杂计算 */;
  cache.set(obj, result);
  return result;
}

🎯 实战应用篇

18. 如何实现一个简单的状态管理?

答案: 使用发布订阅模式实现简单的状态管理。

详解:

class SimpleStore {
  constructor(initialState = {}) {
    this.state = initialState;
    this.listeners = [];
  }
  
  getState() {
    return this.state;
  }
  
  setState(newState) {
    this.state = { ...this.state, ...newState };
    this.notify();
  }
  
  subscribe(listener) {
    this.listeners.push(listener);
    return () => {
      this.listeners = this.listeners.filter(l => l !== listener);
    };
  }
  
  notify() {
    this.listeners.forEach(listener => listener(this.state));
  }
}

// 使用示例
const store = new SimpleStore({ count: 0, user: null });

// 订阅状态变化
const unsubscribe = store.subscribe((state) => {
  console.log('状态更新:', state);
});

// 更新状态
store.setState({ count: 1 });
store.setState({ user: { name: 'John' } });

// 取消订阅
unsubscribe();

19. 如何实现深拷贝?

答案: 使用递归、JSON方法或第三方库实现深拷贝。

详解:

// 1. JSON方法(简单但有限制)
function deepCloneJSON(obj) {
  return JSON.parse(JSON.stringify(obj));
}

// 限制:不能处理函数、undefined、Symbol、循环引用

// 2. 递归实现
function deepClone(obj, hash = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }
  
  if (obj instanceof Date) {
    return new Date(obj.getTime());
  }
  
  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }
  
  if (hash.has(obj)) {
    return hash.get(obj);
  }
  
  const clone = Array.isArray(obj) ? [] : {};
  hash.set(obj, clone);
  
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key], hash);
    }
  }
  
  return clone;
}

// 使用示例
const original = {
  name: 'John',
  age: 30,
  hobbies: ['reading', 'gaming'],
  address: {
    city: 'New York',
    country: 'USA'
  },
  birthday: new Date('1990-01-01'),
  regex: /test/g
};

const cloned = deepClone(original);
console.log(cloned);

20. 如何实现防抖和节流?

答案: 防抖是延迟执行,节流是限制执行频率。

详解:

// 防抖 - 延迟执行
function debounce(func, delay) {
  let timeoutId;
  
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}

// 节流 - 限制频率
function throttle(func, limit) {
  let inThrottle;
  
  return function(...args) {
    if (!inThrottle) {
      func.apply(this, args);
      inThrottle = true;
      setTimeout(() => {
        inThrottle = false;
      }, limit);
    }
  };
}

// 使用示例
const debouncedSearch = debounce((query) => {
  console.log('搜索:', query);
}, 300);

const throttledScroll = throttle(() => {
  console.log('滚动事件');
}, 100);

// 输入框搜索
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', (e) => {
  debouncedSearch(e.target.value);
});

// 滚动事件
window.addEventListener('scroll', throttledScroll);

📝 总结

本文整理了50道JavaScript核心概念和ES6+新特性的高频面试题,涵盖了:

基础知识:数据类型、变量提升、事件循环等 ✅ 核心概念:作用域、闭包、原型链、this等 ✅ 异步编程:Promise、async/await等 ✅ ES6+特性:箭头函数、解构赋值、模板字符串等 ✅ 模块化:ES6模块系统 ✅ 性能优化:DOM操作、内存管理、防抖节流等 ✅ 实战应用:状态管理、深拷贝、工具函数等

面试建议:

  1. 理解原理:深入理解JavaScript的运行机制
  2. 实践练习:多动手实现各种功能
  3. 关注新特性:了解ES6+的新特性和使用场景
  4. 性能意识:在开发中始终考虑性能问题

学习资源:

希望这些面试题能帮助你在前端面试中取得好成绩!🚀


💡 小贴士:面试时不仅要回答正确,更要展示你的思考过程和实践经验。多准备一些实际项目的例子,这样会让你的回答更有说服力!

标签: #前端面试 #JavaScript #ES6 #面试题 #前端开发 #Web开发