乐闻世界logo
搜索文章和话题

前端面试题手册

在 Vue 中,watch和watchEffect的区别是什么?

在Vue中,watch和watchEffect是两种响应式侦听器,都能够对响应式状态的变化作出反应,但是它们的工作方式和使用场景有所不同。watchwatch API 允许我们侦听特定的数据源,并在数据源改变时执行回调函数。它是响应式系统的一部分,非常适合于执行异步操作或比较昂贵的操作,因为你可以精确控制何时以及如何响应状态的变化。精确性: watch允许你指定确切的响应式引用或计算属性来侦听。懒执行: watch默认情况下不会立即执行回调,它只会在侦听的响应式源发生变化时才执行。深度监听: watch可以配置为深度监听,侦听对象内部属性的变化。旧值和新值: watch回调提供新旧值,便于比较。停止监听: watch返回一个停止观察函数,你可以用它来停止监听。例子:<template> <div>{{ count }}</div></template><script>export default { data() { return { count: 0 } }, watch: { count(newVal, oldVal) { // 当 count 改变时,这个函数将被调用 console.log(`Count changed from ${oldVal} to ${newVal}`); } }}</script>watchEffectwatchEffect是一个响应式侦听器,它自动追踪它的函数内部使用的任何响应式状态,当这些状态改变时会重新执行该函数。自动追踪: watchEffect会自动侦听函数内部所有的响应式引用,并在引用更新时重新运行。立即执行: watchEffect在创建时会立即执行一次,确保响应式效果与当前的状态同步。无需指定侦听源: 不需要像watch那样指定侦听的具体状态,它会自动收集依赖。无旧值: watchEffect不提供旧值,因为它不侦听特定的数据源。停止监听: watchEffect同样返回一个停止监听的函数。例子:<template> <div>{{ count }}</div></template><script>import { ref, watchEffect } from 'vue';export default { setup() { const count = ref(0); watchEffect(() => { // 这个函数会在 setup() 时立即执行一次,并在 count 改变时再次执行 console.log(`Count is now: ${count.value}`); }); return { count }; }}</script>总结一下,watch更适用于当你需要侦听特定数据并在变化时进行比较或执行复杂逻辑时,而watchEffect则更适用于当你希望自动追踪并响应响应式状态变化,而不需要过多地控制侦听源和执行时机时。
阅读 127·2024年6月24日 16:43

Vite 为什么启动非常快

Vite 之所以能快速启动,主要得益于它的两个核心设计理念:使用原生 ES 模块(ESM)和按需编译。原生 ES 模块加载(ESM):Vite 利用现代浏览器支持的原生 ES 模块特性来服务模块。在开发模式下,Vite 作为一个由浏览器原生支持的模块服务器,它不需要对代码进行打包和构建,而是通过 <script type="module"> 直接加载模块。这样可以快速启动服务器,并且在请求代码时,浏览器只需加载需要的模块,而不是整个应用程序的打包文件。按需编译:当使用传统的打包工具时,比如 Webpack,整个应用的所有依赖在启动时都需要先被打包,这包括了构建第三方库和应用代码。这个过程需要时间,特别是当应用规模庞大时。与此相反,Vite 在开发模式下采用了按需编译的策略。这意味着只有当请求某个文件时,Vite 才会对这个文件进行编译和处理。这种方式显著减少了启动时间,并且能够快速响应代码的热更新。缓存优化:Vite 对依赖的预构建过程进行了优化。它会在第一次运行时将所有的依赖项编译成 ESM,并将结果缓存起来。在随后的启动中,如果没有依赖变化,它会直接使用缓存的结果而不是重新编译,这进一步提高了启动速度。快速的 HMR(热模块替换):Vite 的热模块替换是模块级别的,当文件发生变化时,只有那个文件和依赖它的链会被重新加载和编译。这比 Webpack 这样的打包器进行整体刷新要快得多。高效的依赖预打包(Pre-bundling):对于某些复杂的依赖(如 CommonJS 或者依赖其他模块的库),Vite 使用 esbuild 预打包这些依赖。esbuild 是用 Go 语言编写的,它的打包速度远远超过基于 JavaScript 的打包器,如 webpack 和 Rollup。例如,假设你有一个具有数百个模块的大型应用程序。在传统的打包器中,即使你只修改了一个模块,也需要重新打包整个应用程序,这可能需要几十秒甚至更长时间。而在 Vite 中,如果你修改了一个模块,只有这个模块会被重新编译和返回,因此你几乎可以立即看到变化,从而极大提高了开发效率。总的来说,Vite 之所以能够实现快速的启动,是因为它摈弃了在开发阶段不必要的打包步骤,采用了更现代的模块加载方式,并通过智能的缓存和预编译策略来提高效率。这些设计理念使得 Vite 在开发过程中能够提供极致的快速响应体验。
阅读 17·2024年6月24日 16:43

如何广度优先遍历DOM树?

广度优先遍历(Breadth-First Traversal, BFT)是一种遍历或搜索树或图结构的算法,它从根节点开始,然后遍历所有邻近的节点,再对每个邻近节点做同样的处理,依此类推,直到遍历完所有可达的节点。在DOM树中应用广度优先遍历同样遵循这个原则,其中DOM树的根节点通常是document对象的documentElement属性,通常指向HTML文档的<html>元素。在JavaScript中执行DOM树的广度优先遍历,我们可以使用队列(Queue)这一数据结构来辅助实现。以下是一个简单的例子:function breadthFirstTraversal(root) { // 创建一个队列,并将根节点入队 let queue = [root]; // 当队列不为空时,循环执行 while (queue.length > 0) { // 出队一个节点并访问 let currentNode = queue.shift(); console.log(currentNode.tagName); // 打印当前节点的标签名 // 将当前节点的所有子节点入队 [].slice.call(currentNode.children).forEach(child => { queue.push(child); }); }}// 调用函数,传入document.documentElement作为遍历的起点breadthFirstTraversal(document.documentElement);在这个例子中,我定义了一个名为breadthFirstTraversal的函数,它接收一个DOM节点作为遍历的起点。然后,我使用一个数组作为队列来存放待访问的节点。在while循环中,我不断地从队列中取出节点,访问它,并将它的子节点加入队列末尾。通过这种方式,我能够按照广度优先的顺序访问整个DOM树的每一个节点。这个例子中,console.log(currentNode.tagName)是对当前节点的访问方式,实际应用中可以替换为其他操作,比如获取或修改节点信息等。此外,.slice.call(currentNode.children)是一种常见的技巧,用来将HTMLCollection或NodeList对象转换为数组,以便使用数组的forEach方法。在现代的JavaScript中,你也可以直接使用Array.from(currentNode.children)来进行转换。
阅读 29·2024年6月24日 16:43

html meta标签如何把http换成https的?

在HTML中,meta 标签本身并不直接将 HTTP 切换到 HTTPS。meta 标签通常用于定义网页文档的元数据,比如页面描述、关键字、文档的作者、最后修改时间以及其他元数据。这些元数据不会直接显示在页面上,但会被搜索引擎和浏览器用于处理网页数据。将网站从 HTTP 协议切换到更安全的 HTTPS 协议,通常需要在服务器层面上进行配置,而不是通过 HTML。这通常包括以下几个步骤:购买和安装 SSL/TLS 证书:首先,您需要为您的网站购买 SSL(Secure Sockets Layer)或 TLS(Transport Layer Security)证书。这些证书可以从证书颁发机构(CA)获得,它能够为你的网站提供加密,从而确保数据安全传输。配置 Web 服务器:安装证书之后,您需要配置您的 Web 服务器(比如 Apache、Nginx、IIS 等)来使用这个证书,并启动 HTTPS 协议。这通常涉及到编辑服务器配置文件来指定证书的位置,并设置服务器监听 443 端口(HTTPS 默认端口)的请求。重定向所有 HTTP 请求到 HTTPS:为了确保用户访问的是 HTTPS 版本的网站,您需要设置 HTTP 到 HTTPS 的重定向。在 Web 服务器配置中,您可以设置规则来自动将所有 HTTP 请求重定向到 HTTPS。例如,在 Apache 服务器中,您可以使用 .htaccess 文件来设置重定向规则,如下: RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]在上面的例子中,如果用户访问的是 HTTP 版本的网站,服务器将会发送一个 HTTP 状态码为 301(永久重定向)的响应,告诉浏览器该资源已经被永久地移动到了对应的 HTTPS URL。虽然 meta 标签不能用于切换 HTTP 到 HTTPS,但它有一个相关的用途,那就是设置 HTTP 的内容安全策略(Content Security Policy, CSP)。通过 CSP,您可以使用 meta 标签来增强网站的安全性。例如:<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">这个 meta 标签的作用是指示兼容的浏览器自动将页面上所有可用的不安全 URL(HTTP)请求升级为安全的 URL(HTTPS)。这不是将整个站点从 HTTP 切换到 HTTPS 的方法,而是一个辅助措施,用于提高页面中单独资源请求的安全性。
阅读 24·2024年6月24日 16:43

fetch 和 xhr 有什么区别?

Fetch API和XMLHttpRequest(XHR)都是用于在浏览器中发起HTTP请求的技术。 XMLHttpRequest (XHR):历史悠久: XHR出现的比较早,它是Ajax技术的基石,自2000年代初以来一直被广泛使用。复杂性: XHR的API相对复杂,使用时需要管理不同的事件和状态变化。支持状态: 它支持对请求的细粒度控制,比如可以在下载过程中监控进度事件。灵活性: XHR允许同步和异步通信。兼容性: 它的兼容性很好,支持老旧的浏览器。Fetch API:现代替代: Fetch是一个现代化的替代方案,提供了更简单、更强大的方式来发起网络请求。基于Promise: Fetch API基于Promise,这使得异步操作更加简洁,易于管理。语法简洁: Fetch提供了一个更加简洁和清晰的API,易于阅读和写作。无需额外的库: 与XHR配合一些库(如jQuery)使用相比,Fetch不需要额外的库或框架。默认异步: Fetch只支持异步操作,这有助于防止阻塞用户界面的问题。例子:使用XHR发起GET请求的代码可能如下:var xhr = new XMLHttpRequest();xhr.open('GET', 'https://api.example.com/data', true);xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { console.log(xhr.responseText); }};xhr.send();而使用Fetch API完成同样的任务的代码则更加简洁:fetch('https://api.example.com/data') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error(error));Fetch API的优势在于它的简洁性和基于Promise的结构,这使得异步编码更加直观和易于维护。同时,Fetch还支持Request和Response接口,这有利于进一步控制请求和响应的细节。不过,对于一些需要细粒度控制的场合,或者在需要支持老旧浏览器的环境下,XHR仍然是一个可行的选择。
阅读 25·2024年6月24日 16:43

能不能说说 AMD 和 ESModule 有什么区别? ESModule 对于 Tree-Shaking 有什么优势呢?

AMD(Asynchronous Module Definition)和ESModule(ECMAScript Module)是JavaScript中的两种不同的模块化标准。这两者之间存在几个关键区别: AMD(Asynchronous Module Definition)异步加载: AMD是设计用来支持浏览器中的异步模块加载。它允许模块和它们的依赖项可以在不阻塞页面渲染的情况下被异步加载。动态加载: AMD模块可以在运行时动态加载,这意味着你可以根据需要随时加载模块。模块定义: AMD模块被定义为一个函数,这个函数接受一个依赖数组和一个工厂函数。工厂函数返回模块的导出值。实现库: 代表性的实现库是RequireJS。例如,使用AMD定义一个模块可能是这样的: define(['dependency1', 'dependency2'], function (dep1, dep2) { function myModuleFunction() { // 使用依赖项的代码 } return myModuleFunction; });ESModule(ECMAScript Module)静态结构: ESModules设计为具有静态结构,这意味着模块的导入和导出必须位于模块的顶层,并且不能动态改变。同步和异步加载: ESModules可以被同步加载,也可以被异步加载。在浏览器中,可以使用 <script type="module">标签异步加载模块。模块语法: ESModules使用 import和 export语法直接在JavaScript语言层面进行模块化。原生支持: 现代的浏览器和最新的Node.js版本都原生支持ESModules。例如,使用ESModule导入和导出可能是这样的: // 导入 import { myFunction } from './myModule.js'; // 导出 export function myFunction() { // 函数实现 }Tree-Shaking 的优势Tree-Shaking是一种用于移除JavaScript中未被使用代码(dead code)的技术。ESModule的静态结构特性让工具(如Webpack和Rollup)可以在构建时静态分析代码中的导入和导出,这样可以更容易地确定哪些代码是未被使用的。由于AMD是动态的,模块依赖在运行时解析,这使得确定未使用代码变得更加困难。因此,ESModule由于其静态结构,在进行Tree-Shaking时更有效,可以更好地优化最终的bundle大小。Tree-Shaking的工作方式有赖于导入语句在代码中的位置,以及它们是否被其他代码引用。由于ESModule的 import和 export语句是静态的,构建工具可以在打包过程中准确地识别并去除那些未被使用的导出,这样就可以减少最终包(bundle)的大小并提升加载性能。
阅读 28·2024年6月24日 16:43

CSS 中 display有哪些值?并且说明它们的作用?

CSS中的display属性非常关键,主责决定一个元素如何被展示在页面上。以下是几个常见的display属性值以及它们的作用:none:此值使元素不显示,并从文档布局中完全移除,就好像它从未存在一样,不占据任何空间。例子:当你想隐藏一些内容,而不影响页面布局时,可以使用display: none;。.hidden-element { display: none;}block:它将元素显示为块级元素,这意味着元素会新起一行显示,并且尽可能占满父元素的宽度。例子:默认的<div>、<p>、<h1>到<h6>等都是块级元素。.block-element { display: block;}inline:元素不会新起一行,其宽度仅由内容决定,多个inline元素可以在同一行显示。例子:<span>、<a>、<strong>等元素默认是内联元素。.inline-element { display: inline;}inline-block:结合了inline和block的特点,让元素既可以在同一行显示,同时又可以设置宽高。例子:适用于需要在同一行显示的按钮或菜单项,而且还需要设定尺寸。.menu-item { display: inline-block;}flex:将元素设置为弹性容器,其子元素会成为弹性项目。这个值允许使用flexbox布局,可以提供更复杂的布局结构和对齐方式。例子:可以创建一个水平或垂直的导航栏,其中的项可以均匀地分布空间或对齐。.flex-container { display: flex;}grid:启用网格布局,其中的子元素可以放置在定义的行和列网格中。例子:当你要创建一个复杂的页面布局,例如一个有多列和明确对齐方式的仪表盘界面。.grid-container { display: grid;}table:类似于HTML的<table>,将元素表现为表格相关的元素,如<table>,<tr>, <td>等。例子:当你需要使用CSS而不是HTML标签来创建表格布局时。.table-like { display: table;}这些只是display属性中的几个值,实际上还有很多其他值,如list-item、table-row、table-cell等,它们可以用于更专门的布局需求。不同的display设置对布局、文档流和元素间的关系有着直接的影响。
阅读 57·2024年6月24日 16:43