JavaScript 深入理解 - 2024 年前端面试技巧与面试题汇总
JavaScript 是前端开发的核心,无论你使用哪种框架或库,面试中都离不开对 JavaScript 的考察。本篇将深入讲解 JavaScript 常见的面试题目及其背后的原理,帮助你在面试中从容应对复杂问题,展现扎实的基础功底。
1. 闭包(Closure)
(1) 什么是闭包?
问:闭包的定义是什么?它的常见应用场景有哪些?
答:闭包是指函数能够“记住”并访问它的词法作用域(lexical scope)中的变量,即使函数在它的定义作用域之外执行。换句话说,闭包是在一个函数内部定义的另一个函数,内部函数可以访问外部函数的变量和参数,甚至在外部函数执行完毕后依然可以访问。
常见应用场景:
- 数据封装:通过闭包实现私有变量,外部无法直接访问或修改这些变量。
- 回调函数:如事件处理函数、定时器函数中的闭包。
- 柯里化:函数接收部分参数后返回一个新函数,后续传入更多参数继续执行。
示例:
function createCounter() {
let count = 0; // 外部函数作用域中的变量
return function() {
// 内部函数形成闭包
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 输出: 1
console.log(counter()); // 输出: 2
2. 原型链与继承
(2) 什么是原型链?
问:JavaScript 中的原型链如何工作?如何实现继承?
答:原型链是 JavaScript 实现继承的一种方式。在 JavaScript 中,每个对象都有一个 __proto__
属性,指向它的原型对象,而原型对象又有自己的 __proto__
,依此类推,形成一个原型链。当访问对象的某个属性时,如果对象本身没有这个属性,JavaScript 会沿着原型链向上查找,直到找到该属性或到达原型链的尽头。
继承的实现:
- 构造函数继承:通过将子类构造函数中的
this
绑定到父类构造函数来继承属性。 - 原型继承:通过设置子类的原型对象为父类的实例对象来继承方法。
示例:
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(`${
this.name} makes a sound.`);
};
function Dog(name) {
Animal.call(this, name); // 调用父类构造函数继承属性
}
Dog.prototype = Object.create(Animal.prototype); // 继承父类方法
Dog.prototype.constructor = Dog;
const dog = new Dog('Rex');
dog.speak(); // 输出: Rex makes a sound.
3. 作用域与作用域链
(3) 什么是作用域链?
问:JavaScript 中如何工作作用域链?为什么它很重要?
答:作用域链是在 JavaScript 中查找变量的一种机制。当在一个函数中访问一个变量时,JavaScript 会首先在当前函数的作用域中查找,如果未找到则沿着作用域链依次向上查找,直到全局作用域。
作用域链的主要功能是保证变量的可见性和隔离性,防止不同作用域中的变量发生冲突。
示例:
let globalVar = 'global';
function outerFunction() {
let outerVar = 'outer';
function innerFunction() {
let innerVar = 'inner';
console.log(globalVar); // 输出: global
console.log(outerVar); // 输出: outer
console.log(innerVar); // 输出: inner
}
innerFunction();
}
outerFunction();
4. 事件循环(Event Loop)
(4) 什么是事件循环?
问:JavaScript 的事件循环是如何工作的?它与异步操作有何关系?
答:JavaScript 是单线程语言,它通过事件循环来管理异步操作。事件循环的主要作用是监控任务队列(task queue)中的任务,并将任务推入执行栈中运行。
- 同步任务:直接在调用栈中按顺序执行。
- 异步任务:如
setTimeout
、Promise
等,会先被推入任务队列中,当调用栈为空时,事件循环会检查任务队列,将任务推入调用栈执行。
事件循环执行顺序:
- 执行所有同步代码。
- 遇到异步任务,将其放入任务队列。
- 执行微任务队列中的任务(如
Promise
)。 - 执行宏任务队列中的任务(如
setTimeout
)。
示例:
console.log('Start')