下面是详细讲解“你有必要知道的25个JavaScript面试题”的完整攻略。
介绍
在面试过程中,JavaScript是一个非常重要的方面,掌握常见的JavaScript面试题可以帮助我们更好地准备面试。这里整理了25个常见的JavaScript面试题供大家参考。
问题列表
1. typeof null
返回什么?
typeof null
返回 "object"
。请注意,这是JavaScript中一个已知的错误。
2. 如何将变量从一个文件导出并在另一个文件中使用?
一个常见的方式是使用 export
关键字将变量或函数导出,并使用 import
关键字在另一个文件中导入并使用它们。例如:
// 导出变量
export const name = "Jenny";
// 导出函数
export function add(a, b) {
return a + b;
}
在另一个文件中使用导入:
// 导入变量和函数
import { name, add } from "./example.js";
console.log(name); // 输出 Jenny
console.log(add(2, 5)); // 输出 7
3. 什么是闭包?
闭包是指一个函数能够访问并操作其外部函数的变量。这是由于JavaScript的词法作用域和函数可以在其定义的作用域之外执行的特性所导致的。
function greet(name) {
let message = `Hello, ${name}!`;
function getMessage() {
return message;
}
return getMessage;
}
const greeting = greet("Jenny");
console.log(greeting()); // 输出 Hello, Jenny!
这里,函数 greet
返回了 getMessage
函数,它可以访问外部函数 greet
中的变量 message
。
4. undefined
和 null
的区别是什么?
undefined
表示一个变量未赋值或未定义。null
表示一个变量的值为 null
,即空对象引用。在布尔上下文中,它们都被认为是假值。
5. JavaScript 中有哪些类型?
JavaScript 中有六种类型:undefined
、null
、string
、number
、boolean
和 object
。ES6 中新增了一种类型,Symbol
。
6. 如何检查一个变量的类型?
可以使用 typeof
操作符来检查一个变量的类型:
const x = "Hello, world!";
console.log(typeof x); // 输出 string
7. 如何判断一个变量是否是数组?
可以使用 Array.isArray()
方法来判断一个变量是否是数组:
const arr = [1, 2, 3];
console.log(Array.isArray(arr)); // 输出 true
8. 什么是作用域?
作用域是指变量、函数和对象在代码中可访问的范围。JavaScript 有三种类型的作用域——全局作用域、函数作用域和块级作用域。
9. 什么是变量提升?
变量提升是指在 JavaScript 中,变量和函数声明的声明部分会被提升到当前作用域的顶部。这意味着在变量或函数被声明之前访问它们时,它们已经被初始化为 undefined
。
console.log(name); // 输出 undefined
var name = "Jenny";
10. 什么是事件冒泡?
事件冒泡是指在事件被触发后,它的父元素将依次接收该事件。
<div class="box">
<button>Click me!</button>
</div>
const button = document.querySelector("button");
const box = document.querySelector(".box");
button.addEventListener("click", () => {
console.log("Button clicked");
});
box.addEventListener("click", () => {
console.log("Box clicked");
});
在上面的代码中,当点击按钮时,将会依次触发 button
元素和 box
元素上的单击事件,因此控制台将输出以下两行内容:
Button clicked
Box clicked
11. 什么是事件委托?
事件委托是指将事件处理程序添加到父元素,而不是将它们添加到子元素中,以避免在子元素数目很多的情况下产生垃圾代码。
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Orange</li>
</ul>
const list = document.querySelector("ul");
list.addEventListener("click", event => {
if (event.target.tagName === "LI") {
console.log(event.target.textContent);
}
});
在上面的代码中,单击每个 <li>
元素时,将输出相应元素的文本内容。
12. 什么是深拷贝和浅拷贝?
浅拷贝是指将一个对象的引用复制到另一个对象中,而不是复制对象本身。因此,如果一个对象被更改,另一个对象也将被更改。
深拷贝是指将一个对象的副本复制到另一个对象中,而不是复制对象本身。因此,即使一个对象被更改,另一个对象也不会受到影响。
// 浅拷贝实例
const obj1 = { name: "Jenny", age: 23 };
const obj2 = obj1;
obj2.name = "Lily";
console.log(obj1.name); // 输出 Lily
// 深拷贝实例
const obj3 = { name: "Jenny", age: 23 };
const obj4 = JSON.parse(JSON.stringify(obj3));
obj4.name = "Lily";
console.log(obj3.name); // 输出 Jenny
13. 什么是回调函数?
回调函数是指一个函数作为另一个函数的参数,并在该函数执行完毕后被调用。
function greet(callback) {
console.log("Hello, world!");
callback();
}
greet(() => console.log("Nice to meet you!"));
在上面的代码中,greet
函数接受一个回调函数作为参数,并在输出 Hello, world!
后调用该回调函数。
14. 什么是 Promise?
Promise 是一种异步编程模式,它允许我们在代码执行完毕前处理异步操作的结果。
const promise = new Promise((resolve, reject) => {
const request = new XMLHttpRequest();
request.onreadystatechange = () => {
if (request.readyState === 4 && request.status === 200) {
resolve(request.responseText);
} else if (request.readyState === 4) {
reject("An error occurred");
}
};
request.open("GET", "https://jsonplaceholder.typicode.com/todos/1");
request.send();
});
promise.then(response => console.log(response)).catch(error => console.log(error));
在上面的代码中,Promise
的构造函数接受一个函数,该函数将使用异步操作并为异步操作提供一个 resolve
和一个 reject
参数。我们可以使用 then
和 catch
方法分别处理异步操作的结果。
15. 什么是闭包?
闭包是指一个函数能够访问并操作其外部函数的变量。这是由于JavaScript的词法作用域和函数可以在其定义的作用域之外执行的特性所导致的。
function greet(name) {
let message = `Hello, ${name}!`;
function getMessage() {
return message;
}
return getMessage;
}
const greeting = greet("Jenny");
console.log(greeting()); // 输出 Hello, Jenny!
16. 什么是 JavaScript 中的 this 关键字?
this
关键字是指当前正在执行的函数所属的对象。如果函数被作为对象的方法调用,则 this
指向该对象。否则,它指向全局对象。
const person = {
name: "Jenny",
greet() {
console.log(`Hello, my name is ${this.name}!`);
}
};
person.greet(); // 输出 Hello, my name is Jenny!
在上面的代码中,当 greet
方法被调用时,this
指向 person
对象。
17. 如何取消 Promise?
可以使用 Promise.race()
方法创建一个新的 Promise,该 Promise 将与原始 Promise 竞争,并在其中一个 Promise 解决或拒绝时解决或拒绝。
const promise1 = new Promise(resolve => setTimeout(resolve, 3000));
const promise2 = new Promise((resolve, reject) =>
setTimeout(() => reject("Timed out"), 5000)
);
Promise.race([promise1, promise2])
.then(() => console.log("Promise resolved"))
.catch(error => console.log(error)); // 输出 Timed out
在上面的代码中,两个 Promise 将竞争,并在 promise2
超时时拒绝。Promise.race()
将处理第一个解决或拒绝的 Promise。
18. JavaScript 中的防抖和节流是什么?
防抖和节流都是一些处理 JavaScript 事件性能问题的技术。
防抖是指在触发事件后等待一段时间再执行处理程序,如果在等待时间内再次触发该事件,则重新开始计时。这是为了避免处理程序被过度调用的问题。
function debounce(func, delay) {
let timeout;
return function() {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, arguments);
}, delay);
};
}
const handleInput = debounce(() => console.log("Input event occurred"), 1000);
document.addEventListener("input", handleInput);
在上面的代码中,debounce
函数将返一个新函数,该函数使用 setTimeout
延迟执行处理程序。如果在 delay
时间内再次触发该事件,则 setTimeout
将被取消并重新启动。
节流是指在一段时间内只允许一个事件被触发。如果更多事件触发,则将被忽略,这是为了避免处理程序被多次调用的问题。
function throttle(func, delay) {
let timeout;
let lastRun = 0;
return function() {
const context = this;
const args = arguments;
if (Date.now() - lastRun >= delay) {
func.apply(context, args);
lastRun = Date.now();
} else {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args);
lastRun = Date.now();
}, delay - (Date.now() - lastRun));
}
};
}
const handleScroll = throttle(() => console.log("Scroll event occurred"), 1000);
document.addEventListener("scroll", handleScroll);
在上面的代码中,throttle
函数将返一个新函数,该函数在 delay
时间内只允许一个事件被触发。如果更多事件被触发,则将被忽略。
19. 什么是 JavaScript 的事件循环?
事件循环是指在 JavaScript 中处理异步事件的方式,它是由浏览器提供的。
事件循环是单个线程的。它持续监听待处理的事件队列,并在队列中发现可用事件时处理它们。
console.log("Start");
setTimeout(() => console.log("Timeout"), 0);
Promise.resolve().then(() => console.log("Promise"));
console.log("End");
在上面的代码中,setTimeout
和 Promise
都是异步的。setTimeout 的延迟时间是0,这意味着它将在当前事件循环的末尾处理。Promise 的 resolve 函数显式调用,将它添加到当前事件循环的末尾。因此,控制台将输出以下内容:
Start
End
Promise
Timeout
20. 什么是 JavaScript 中的事件捕获?
事件捕获是指从根元素开始向下指定元素的过程,直到达到正在监听事件的元素。这允许在事件到达指定元素之前对其进行处理。
<div class="box">
<button>Click me!</button>
</div>
const button = document.querySelector("button");
const box = document.querySelector(".box");
button.addEventListener(
"click",
() => console.log("Button clicked"),
{ capture: true }
);
box.addEventListener("click", () => console.log("Box clicked"));
// 输出顺序:
// Box clicked
// Button clicked
在上面的代码中,单击按钮时,首先处理的是 box
元素的单击事件,因为它将从根元素向下处理事件。即使按钮的事件被声明为在捕获阶段处理 ({ capture: true }
),该事件仍在冒泡阶段处理。
21. 什么是 JavaScript 中的事件监听?
事件监听是指使用 addEventListener()
方法将处理程序添加到事件的元素中。该方法允许我们指定要监听的事件类型、处理程序函数和是否使用事件捕获。
<button>Click me!</button>
const button = document.querySelector("button");
button.addEventListener("click", () => console.log("Button clicked"));
在上面的代码中,单击按钮时将触发 click
事件,并将处理程序添加到事件的按钮元素中。
22. 什么是闭包?
闭包是指一个函数能够访问并操作其外部函数的变量。这是由于JavaScript的词法作用域和函数可以在其定义的作用域之外执行的特性所导致的。
function greet(name) {
let message = `Hello, ${name}!`;
function getMessage() {
return message;
}
return getMessage;
}
const greeting = greet("Jenny");
console.log(greeting()); // 输出 Hello, Jenny!
在上面的代码中,函数 greet
返回了 getMessage
函数,它可以访问外部函数 greet
中的变量 message
。
23. 什么是 Web Workers?
Web Workers 是一种浏览器 API,它允许我们在后台线程中运行 JavaScript 代码。这可以提高应用程序的性能并避免阻塞UI线程。
可以使用 new Worker()
构造函数创建 Web Worker,并且可以使用 postMessage()
方法将消息发送到 Worker 中,并使用 onmessage
事件处理程序接收来自 Worker 的消息。
// 声明一个新的 Worker
const worker = new Worker("worker.js");
// 向 Worker 发送一条消息
worker.postMessage("Hello, worker!");
// 处理来自 Worker 的消息
worker.onmessage = event => console.log(event.data);
在上面的代码中,worker.js
是一个包含 Worker 代码的文件。 Worker 将在后台线程中运行,因此可以发送和接收消息而不会对UI阻塞。
24. JavaScript 中的值和引用有什么区别?
JavaScript 中的值是指所有基本类型(如字符串、数字、布尔值和空值),它们的值是直接存储在变量中的。
JavaScript 中的引用是指所有复杂数据类型(如对象、数组和函数),它们的值是存储在内存中的地址,而不是存储在变量中的值。因此,当引用一个对象或其他复杂
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:你有必要知道的25个JavaScript面试题 - Python技术站