领悟JS经典面试题,进阶前端开发之路
2024-02-13 19:31:50
前言
JavaScript (JS) 作为一门流行的编程语言,在前端开发领域发挥着至关重要的作用。它能够为网页带来交互性、动画效果和动态内容。因此,对于前端开发人员来说,掌握JS是必不可少的。在求职面试中,JS也是经常被问到的一个话题。
经典JS面试题
为了帮助您更好地理解JS并为面试做好准备,我整理了一些经典的JS面试题,涵盖基础和高级水平。这些问题旨在测试您对JS核心概念和原理的掌握程度,并帮助您发现自己的知识盲点。
基础题
- 什么是JS中的闭包?
- JS中的原型链是什么?
- JS中的事件循环是如何工作的?
- JS中的作用域是如何划分的?
- JS中的变量提升是如何工作的?
- JS中的this是什么?
高级题
- 如何在JS中创建自定义事件?
- 如何在JS中使用代理模式?
- 如何在JS中使用发布/订阅模式?
- 如何在JS中使用模块化编程?
- 如何在JS中使用异步编程?
解答与示例
基础题解答
-
闭包
闭包是指一个内部函数可以访问其外部函数作用域中的变量,即使外部函数已经执行完毕。闭包的存在使得我们可以访问外部函数的作用域,从而实现一些特殊的效果。例如,闭包可以被用来实现私有变量、柯里化函数、惰性求值等等。
function outer() { let count = 0; function inner() { count++; console.log(count); } return inner; } const innerFunction = outer(); innerFunction(); // 1 innerFunction(); // 2 innerFunction(); // 3
在这个例子中,内部函数inner()可以访问外部函数outer()中的变量count,即使outer()已经执行完毕。每次调用inner(),count的值都会增加1。
-
原型链
原型链是指对象继承的一种机制。在JS中,每个对象都有一个原型对象,该原型对象包含了该对象的所有属性和方法。如果一个对象没有某个属性或方法,它会沿着原型链向上查找,直到找到该属性或方法。
const person = { name: 'John Doe', age: 30 }; const employee = { salary: 100000 }; employee.__proto__ = person; console.log(employee.name); // John Doe console.log(employee.age); // 30 console.log(employee.salary); // 100000
在这个例子中,employee对象继承了person对象的属性和方法。当我们访问employee对象的name和age属性时,会直接找到这些属性的值。而当我们访问employee对象的salary属性时,会沿着原型链向上查找,直到找到该属性。
-
事件循环
事件循环是指JS运行时的一种机制,它负责处理事件并执行相应的任务。事件循环是一个不断重复的过程,它不断地从事件队列中获取事件,然后执行相应的事件处理函数。
setTimeout(() => { console.log('This will be executed after 1 second'); }, 1000); console.log('This will be executed immediately');
在这个例子中,setTimeout()函数将一个事件添加到事件队列中,该事件将在1秒后执行。console.log()函数则会立即执行。因此,上面的代码会先输出"This will be executed immediately",然后在1秒后输出"This will be executed after 1 second"。
-
作用域
作用域是指一个变量或函数可以被访问的范围。在JS中,作用域分为全局作用域和局部作用域。全局作用域是指在整个程序中都可以访问的变量或函数,而局部作用域是指只在某个特定块或函数中可以访问的变量或函数。
let globalVariable = 10; function outer() { let localVariable = 20; function inner() { console.log(globalVariable); console.log(localVariable); } inner(); } outer();
在这个例子中,globalVariable是全局变量,可以在outer()函数和inner()函数中访问。localVariable是局部变量,只能在outer()函数和inner()函数中访问。
-
变量提升
变量提升是指在JS中,变量的声明会被提升到函数或块的顶部。这意味着,变量可以在声明之前使用。然而,变量提升只对变量的声明有效,而对变量的赋值没有影响。
console.log(x); // undefined var x = 10;
在这个例子中,x被提升到了函数的顶部,但它的值还没有被赋值。因此,当我们尝试在声明之前使用x时,它的值为undefined。
-
this关键字
this关键字是指当前对象。它的值取决于函数的调用方式。在普通函数中,this的值是全局对象。在对象的方法中,this的值是该对象。在事件处理函数中,this的值是触发该事件的元素。
console.log(this); // Window const person = { name: 'John Doe', age: 30, greet() { console.log(this); // { name: 'John Doe', age: 30 } } }; person.greet(); document.addEventListener('click', function() { console.log(this); // <html> });
在这个例子中,this的值取决于函数的调用方式。在第一行,this的值是全局对象。在第二行,this的值是person对象。在第三行,this的值是触发click事件的元素。
高级题解答
-
如何创建自定义事件?
可以通过使用CustomEvent()构造函数来创建自定义事件。该构造函数接受两个参数:事件类型和事件数据。
const customEvent = new CustomEvent('my-custom-event', { detail: { data: 'Hello world!' } }); dispatchEvent(customEvent);
在这个例子中,我们创建了一个名为my-custom-event的自定义事件,并使用detail属性传递了数据。然后,我们使用dispatchEvent()方法触发了该事件。
-
如何使用代理模式?
代理模式是一种设计模式,它允许我们在对象之间创建一个间接的引用。这使得我们可以更灵活地控制对对象的访问,并隔离对象之间的耦合。
class RealSubject { doSomething() { console.log('RealSubject: Doing something...'); } } class Proxy { constructor(realSubject) { this.realSubject = realSubject; } doSomething() { console.log('Proxy: Doing something before...'); this.realSubject.doSomething(); console.log('Proxy: Doing something after...'); } } const realSubject = new RealSubject(); const proxy = new Proxy(realSubject); proxy.doSomething();
在这个例子中,Proxy类作为RealSubject类的代理,在RealSubject类的方法执行前后执行了一些额外的操作。
-
如何使用发布/订阅模式?
发布/订阅模式是一种设计模式,它允许对象之间进行松散耦合的通信。发布者对象可以发布事件,而订阅者对象可以订阅这些事件。当发布者对象发布事件时,订阅者对象会自动收到通知并执行相应的处理。
class EventEmitter { constructor() { this.subscribers = []; } subscribe(subscriber) { this.subscribers.push(subscriber); } publish(data) { this.subscribers.forEach(subscriber => subscriber(data));