现代 JavaScript 最佳实践 - 第 2 部分
在本文的第一部分中,我们探讨了现代 JavaScript 的基础知识以及一些基本的最佳实践,以开始编写更清晰、更高效的代码。但作为开发者,我们知道总是有更多东西需要学习和改进。
8. 可选链接 (?.)
在处理对象或嵌套结构时,我们有时需要在尝试访问属性之前检查它是否存在。 可选链接运算符 (?.) 是一个强大的工具,可以简化此任务,避免 null 或未定义值的属性访问错误。
为什么它有用?
想象一下您有一个复杂的对象结构,并且您不确定其中是否存在某些属性。如果没有可选链接,您将必须在每个步骤进行手动检查,这可能会使您的代码更长且可读性较差。使用 ?. 运算符,您可以安全地访问属性并在任何中间属性不存在时获取未定义的值。
基本示例
const producto = {}; const impuesto = producto?.precio?.impuesto; console.log(impuesto); // undefined
在这种情况下,由于产品没有价格属性,因此可选链返回未定义而不是生成错误。
具有更复杂对象的示例
假设您有一个具有不同属性的产品列表,其中一些可能为空或未定义:
const productos = [ { nombre: 'Laptop', detalles: { precio: 1000 } }, { nombre: 'Teléfono', detalles: null }, { nombre: 'Tablet', detalles: { precio: 500, impuesto: 50 } } ]; // Acceso seguro a la propiedad 'impuesto' de cada producto productos.forEach(producto => { const impuesto = producto?.detalles?.impuesto; console.log(impuesto); // undefined, null o el valor real });
在此示例中,可选链允许我们在尝试访问product.details.tax时避免错误,即使详细信息为空或不存在。
它如何改进您的代码?
- 避免对空或未定义属性的访问错误。
- 简化代码,使安全检查更清晰、更具可读性。
- 允许您处理不确定或不完整的数据,这在处理来自 API 或数据库的响应时非常常见。
奖励:可选的函数链接
可选链也可以与函数一起使用,当您的函数可能未在对象上定义时,这非常有用:
const usuario = { nombre: 'Juan', obtenerEdad: null }; const edad = usuario.obtenerEdad?.(); console.log(edad); // undefined
这里,getAge函数是未定义的(它为空),但它不会抛出错误,它只是返回未定义。
9. 使用 async/await 进行异步处理
当您在 JavaScript 中使用异步操作时,例如从 API 获取数据或读取文件,async/await 语法可能是您最好的朋友。 async/await 不是使用 .then() 和 .catch() 中的 Promise,而是允许您以更清晰、更易读的方式编写异步代码,类似于我们编写同步代码的方式。
为什么使用异步/等待?
- 简单性和可读性:您可以避免阅读和维护变得复杂的“承诺链”。
- 更直观的错误处理:使用try/catch处理错误比使用.catch()更清晰。
- 更精确的控制:允许在函数中的任何地方使用await,从而更容易控制更复杂的异步流程。
基本使用示例:
假设我们正在使用一个返回数据的 API。使用 async/await 而不是 .then() 使流程更容易遵循:
const producto = {}; const impuesto = producto?.precio?.impuesto; console.log(impuesto); // undefined
实际示例:从 API 获取数据并将其显示在 UI 中
假设您有一个网页,您需要在其中显示来自 API 的用户信息。以下是如何使用 async/await 获取数据并将其呈现到界面的示例:
const productos = [ { nombre: 'Laptop', detalles: { precio: 1000 } }, { nombre: 'Teléfono', detalles: null }, { nombre: 'Tablet', detalles: { precio: 500, impuesto: 50 } } ]; // Acceso seguro a la propiedad 'impuesto' de cada producto productos.forEach(producto => { const impuesto = producto?.detalles?.impuesto; console.log(impuesto); // undefined, null o el valor real });
对象.values()
返回一个包含对象属性的所有值的数组。当您只需要值而不需要键时,这是完美的。
示例:
const usuario = { nombre: 'Juan', obtenerEdad: null }; const edad = usuario.obtenerEdad?.(); console.log(edad); // undefined
对象.entries()
这是最通用的方法。返回一个数组的数组,其中每个子数组包含一个键及其对应的值。如果您想在一次操作中同时使用键和值,这非常有用。
示例:
async function obtenerDatos() { try { const respuesta = await fetch('https://api.ejemplo.com/datos'); if (!respuesta.ok) { throw new Error('Error al obtener los datos'); } const datos = await respuesta.json(); console.log(datos); } catch (error) { console.error('Error:', error.message); } }
奖励:使用 for...of 进行迭代
您是否知道可以将这些方法与 for...of 结合起来使您的代码更加简洁?这是使用 Object.entries() 的示例:
示例:
// Función para obtener y mostrar los datos de usuarios async function obtenerUsuarios() { try { const respuesta = await fetch('https://api.ejemplo.com/usuarios'); if (!respuesta.ok) { throw new Error('No se pudieron cargar los usuarios'); } const usuarios = await respuesta.json(); mostrarUsuariosEnUI(usuarios); } catch (error) { console.error('Hubo un problema con la carga de los usuarios:', error); alert('Error al cargar los usuarios. Intenta más tarde.'); } } // Función para renderizar usuarios en el HTML function mostrarUsuariosEnUI(usuarios) { const contenedor = document.getElementById('contenedor-usuarios'); contenedor.innerHTML = usuarios.map(usuario => ` <div> <h3> ¿Qué mejoramos con async/await? </h3> <ol> <li> <strong>Manejo claro de errores:</strong> Usamos try/catch para capturar cualquier error que pueda ocurrir durante la obtención de datos, ya sea un problema con la red o con la API.</li> <li> <strong>Código más legible:</strong> La estructura de await hace que el flujo del código se lea de manera secuencial, como si fuera código sincrónico.</li> <li> <strong>Evita el anidamiento:</strong> Con async/await puedes evitar los callbacks anidados (el famoso "callback hell") y las promesas encadenadas.</li> </ol> <p>Usar async/await no solo mejora la calidad de tu código, sino que también hace que sea mucho más fácil depurar y mantener proyectos a largo plazo. ¡Es una herramienta poderosa que deberías incorporar siempre que trabajes con asincronía en JavaScript!</p> <h2> 10. Métodos modernos para objetos </h2> <p>Cuando trabajamos con objetos en JavaScript, es común que necesitemos iterar sobre las claves y los valores, o incluso extraer solo las claves o valores. Los métodos modernos como Object.entries(), Object.values() y Object.keys() hacen que estas tareas sean mucho más fáciles y legibles.</p> <h3> Object.keys() </h3> <p>Este método devuelve un array con todas las claves de un objeto. Es útil cuando solo necesitas acceder a las claves y no a los valores.</p> <p><strong>Ejemplo:</strong><br> </p> <pre class="brush:php;toolbar:false">const obj = { a: 1, b: 2, c: 3 }; const claves = Object.keys(obj); console.log(claves); // ["a", "b", "c"]
这种方法更干净、更容易阅读,特别是当您处理大型或复杂的对象时。
11.使用Map作为非原始键
当需要将值与非字符串或符号的键关联时,请使用Map。它更加健壮,并且保持了键的类型和顺序。
示例:
const producto = {}; const impuesto = producto?.precio?.impuesto; console.log(impuesto); // undefined
12.使用Symbol作为唯一键
符号是一项 JavaScript 功能,允许您创建唯一且不可变的键,当我们需要确保值不会被意外覆盖或访问时,符号是一个强大的工具。符号无法通过 Object.keys()、for...in 或 JSON.stringify() 等方法访问,这使得它们非常适合私有或“隐藏”值。
为什么要使用符号?
当我们使用文本字符串等键创建对象的属性时,可以轻松操作或覆盖它们。然而,即使我们创建同名的符号,符号也能确保每个键都是唯一的。此外,符号不会出现在对象属性枚举中。
基本示例:
const productos = [ { nombre: 'Laptop', detalles: { precio: 1000 } }, { nombre: 'Teléfono', detalles: null }, { nombre: 'Tablet', detalles: { precio: 500, impuesto: 50 } } ]; // Acceso seguro a la propiedad 'impuesto' de cada producto productos.forEach(producto => { const impuesto = producto?.detalles?.impuesto; console.log(impuesto); // undefined, null o el valor real });
在此示例中,hiddenKey 键是唯一的,尽管我们代码的另一部分可以创建另一个 Symbol('hidden'),但它会完全不同,并且不会影响存储在 obj 中的值。
高级示例:将 Symbol 与 Object.defineProperty 组合
您甚至可以将 Symbol 与 Object.defineProperty 一起使用,以更受控制的方式向对象添加属性,确保属性是不可枚举的。
const usuario = { nombre: 'Juan', obtenerEdad: null }; const edad = usuario.obtenerEdad?.(); console.log(edad); // undefined
在此示例中,secretKey 不会出现在对象的键枚举中,这使其成为不应意外访问或修改的“私有”值的理想选择。
注意事项:
- 符号对于避免属性名称冲突非常有用,尤其是在使用第三方库或 API 时。
- 虽然符号并不是严格意义上的“私有”,但它们不可按常规方式访问的事实有助于保护数据的完整性。
- 请注意,Symbol 无法序列化为 JSON,因此如果需要传输数据,请务必正确处理 Symbol 属性。
13. 小心 JSON 和大数字
在 JavaScript 中,处理大量数字可能是一个真正的挑战。 Number 数据类型在准确表示整数方面存在限制:最大安全整数值为 9007199254740991(也称为 Number.MAX_SAFE_INTEGER)。如果您尝试使用大于此值的数字,则可能会失去精度,这可能会导致应用程序出现错误。
例如,假设您从外部 API 收到大量数字:
async function obtenerDatos() { try { const respuesta = await fetch('https://api.ejemplo.com/datos'); if (!respuesta.ok) { throw new Error('Error al obtener los datos'); } const datos = await respuesta.json(); console.log(datos); } catch (error) { console.error('Error:', error.message); } }
如您所见,数字 9007199254740999 被错误地转换为 9007199254741000。如果该数字对您的应用程序至关重要(例如唯一标识符或财务金额),这可能会出现问题。
如何避免这个问题?
一个简单而优雅的解决方案是使用 ECMAScript 2020 中引入的 BigInt 数据类型。BigInt 可以处理更大的数字而不会损失精度。但是,JSON 本身并不处理 BigInt,因此您需要在序列化数字时将其转换为字符串,然后在反序列化时将它们转换回来。
以下是如何做到这一点的示例:
使用 BigInt 和 JSON.stringify 的解决方案
const producto = {}; const impuesto = producto?.precio?.impuesto; console.log(impuesto); // undefined
通过使用这种方法,您可以保持大量数据的准确性,而不会丢失重要数据。当您再次需要该数字时,只需将其转换回 BigInt:
const productos = [ { nombre: 'Laptop', detalles: { precio: 1000 } }, { nombre: 'Teléfono', detalles: null }, { nombre: 'Tablet', detalles: { precio: 500, impuesto: 50 } } ]; // Acceso seguro a la propiedad 'impuesto' de cada producto productos.forEach(producto => { const impuesto = producto?.detalles?.impuesto; console.log(impuesto); // undefined, null o el valor real });
其他策略
如果您不想使用 BigInt 或者考虑性能,另一种策略是简单地将大数字视为 JSON 中的字符串。这避免了精度问题,但代价是必须在代码中进行转换。
示例:
const usuario = { nombre: 'Juan', obtenerEdad: null }; const edad = usuario.obtenerEdad?.(); console.log(edad); // undefined
为什么它很重要?
正确处理大数不仅对于计算的准确性至关重要,而且对于维护数据完整性也至关重要。当您使用您无法完全控制的第三方 API 或系统时,这一点尤其重要。错误解释的数字可能会导致应用程序失败,或更糟糕的是,可能会导致至关重要的数据错误,例如金融交易或数据库中唯一标识符的处理。
记住:不要忽略精度限制。虽然这看起来像是一个小细节,但应用程序可能会以意想不到的方式失败,并且代价高昂。
14. 显式处理 if 语句中的表达式
在 JavaScript 中,if 语句隐式将表达式转换为“真”或“假”值,如果不考虑此行为,可能会导致意外结果。尽管这种行为有时很有用,但建议在比较中明确,以避免细微的错误并提高代码的可读性。
“真”或“假”是什么意思?
- “Falsy” 指的是在条件表达式中求值时被视为等同于 false 的值。示例:0、“”(空字符串)、null、未定义、NaN。
- “Truthy” 是所有非 falsy 的值,即不是上述之一的任何值。示例:0 以外的任何数字、任何非空字符串、对象等
隐式示例(可能会给出意想不到的结果)
const producto = {}; const impuesto = producto?.precio?.impuesto; console.log(impuesto); // undefined
在上面的例子中,条件没有被执行,因为 0 被认为是“假”。然而,当使用更复杂的值时,这种行为可能很难检测到。
明确的示例(更好的可读性)
const productos = [ { nombre: 'Laptop', detalles: { precio: 1000 } }, { nombre: 'Teléfono', detalles: null }, { nombre: 'Tablet', detalles: { precio: 500, impuesto: 50 } } ]; // Acceso seguro a la propiedad 'impuesto' de cada producto productos.forEach(producto => { const impuesto = producto?.detalles?.impuesto; console.log(impuesto); // undefined, null o el valor real });
提示:每当您处理可能为 false 的值(例如 0、null、false 或“”)时,最好在比较中明确。这样您就可以确保逻辑按照您的期望执行,而不是因为隐式类型强制行为。
另一个值不明确的例子
假设您有一个可以为 null 的对象、一个空数组 [] 或一个空对象 {}。如果你这样做:
const usuario = { nombre: 'Juan', obtenerEdad: null }; const edad = usuario.obtenerEdad?.(); console.log(edad); // undefined
虽然 [] (空数组)是一个有效且真实的对象,但如果您不完全理解其行为,它可能会在将来导致混乱。与其依赖隐式强制转换,最好进行更显式的比较,例如:
async function obtenerDatos() { try { const respuesta = await fetch('https://api.ejemplo.com/datos'); if (!respuesta.ok) { throw new Error('Error al obtener los datos'); } const datos = await respuesta.json(); console.log(datos); } catch (error) { console.error('Error:', error.message); } }
为什么它很重要?
通过显式定义条件,可以降低 JavaScript 自动强制导致错误的风险。这种方法使您的代码更清晰、更易读、更可预测。此外,它还提高了可维护性,因为其他人(或将来的你自己)将能够快速理解逻辑,而不必记住 JavaScript 中虚假值的隐式行为。
15. 尽可能使用严格相等(===)
JavaScript 最令人困惑的行为之一来自非严格相等运算符 (==)。该运算符执行所谓的类型强制,这意味着它在比较值之前尝试将它们转换为通用类型。这可能会产生出乎意料的结果并且非常难以调试。
例如:
const producto = {}; const impuesto = producto?.precio?.impuesto; console.log(impuesto); // undefined
这是一种在你开发过程中会让你发疯的事情。 == 运算符将 [] (空数组)与 ![] 进行比较(结果为 false,因为 [] 被视为 true 值,而 ![] 将其转换为 false)。然而,根据 JavaScript 的内部强制规则,这是一个有效的结果,尽管乍一看没有意义。
为什么会发生这种情况?
JavaScript 在比较之前将比较的双方转换为通用类型。在这种情况下,与 ![] 的布尔值相比,空数组 [] 变为 false。这种类型的强制是一个明显的例子,说明了错误的发生是多么微妙和难以识别。
提示:始终使用严格相等
为了避免这些问题,只要有可能,您应该使用严格相等 (===)。不同之处在于这个 运算符不执行类型强制 。这意味着它严格比较变量的值和类型。
const productos = [ { nombre: 'Laptop', detalles: { precio: 1000 } }, { nombre: 'Teléfono', detalles: null }, { nombre: 'Tablet', detalles: { precio: 500, impuesto: 50 } } ]; // Acceso seguro a la propiedad 'impuesto' de cada producto productos.forEach(producto => { const impuesto = producto?.detalles?.impuesto; console.log(impuesto); // undefined, null o el valor real });
更典型的例子
以下是一些更常见的示例,说明非严格相等 (==) 可能会出现问题:
const usuario = { nombre: 'Juan', obtenerEdad: null }; const edad = usuario.obtenerEdad?.(); console.log(edad); // undefined
为什么使用 === 很重要?
- 预测和可靠性: 使用 === 可以让您进行更可预测的比较,而不会出现意外或类型转换。
- 避免难以检测的错误:当您的代码开始变得更大、更复杂时,与类型强制相关的错误可能很难发现和调试。
- 提高代码可读性:当您看到显式比较时,其他开发人员(或将来的您自己)更容易理解您的代码,而不会产生隐式转换的混乱。
以上是现代 JavaScript 最佳实践 - 第 2 部分的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

Python和JavaScript在开发环境上的选择都很重要。1)Python的开发环境包括PyCharm、JupyterNotebook和Anaconda,适合数据科学和快速原型开发。2)JavaScript的开发环境包括Node.js、VSCode和Webpack,适用于前端和后端开发。根据项目需求选择合适的工具可以提高开发效率和项目成功率。
