在本文的第一部分中,我們探討了現代 JavaScript 的基礎知識以及一些基本的最佳實踐,以開始編寫更清晰、更有效率的程式碼。但作為開發者,我們知道總是有更多東西需要學習和改進。
在處理物件或巢狀結構時,我們有時需要在嘗試存取屬性之前檢查它是否存在。 可選連結運算子 (?.) 是一個強大的工具,可以簡化此任務,避免 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時避免錯誤,即使詳細資訊為空或不存在。
可選鏈也可以與函數一起使用,當您的函數可能未在物件上定義時,這非常有用:
const usuario = { nombre: 'Juan', obtenerEdad: null }; const edad = usuario.obtenerEdad?.(); console.log(edad); // undefined
這裡,getAge函數是未定義的(它為空),但它不會拋出錯誤,它只是返回未定義。
當您在 JavaScript 中使用非同步操作時,例如從 API 取得資料或讀取文件,async/await 語法可能是您最好的朋友。 async/await 不是使用 .then() 和 .catch() 中的 Promise,而是允許您以更清晰、更易讀的方式編寫非同步程式碼,類似於我們編寫同步程式碼的方式。
假設我們正在使用一個傳回資料的 API。使用 async/await 而不是 .then() 使流程更容易遵循:
const producto = {}; const impuesto = producto?.precio?.impuesto; console.log(impuesto); // undefined
假設您有一個網頁,您需要在其中顯示來自 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 });
傳回一個包含物件屬性的所有值的陣列。當您只需要值而不需要鍵時,這是完美的。
範例:
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); } }
您是否知道可以將這些方法與 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"]
這種方法更乾淨、更容易閱讀,特別是當您處理大型或複雜的物件時。
當需要將值與非字串或符號的鍵關聯時,請使用Map。它更加健壯,並且保持了鍵的類型和順序。
範例:
const producto = {}; const impuesto = producto?.precio?.impuesto; console.log(impuesto); // undefined
符號是一項 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 一起使用,以更受控制的方式為物件新增屬性,確保屬性是不可枚舉的。
const usuario = { nombre: 'Juan', obtenerEdad: null }; const edad = usuario.obtenerEdad?.(); console.log(edad); // undefined
在此範例中,secretKey 不會出現在物件的鍵枚舉中,這使其成為不應意外存取或修改的「私有」值的理想選擇。
在 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,因此您需要在序列化數字時將其轉換為字串,然後在反序列化時將它們轉換回來。
以下是如何做到這一點的範例:
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 或系統時,這一點尤其重要。錯誤解釋的數字可能會導致應用程式失敗,或更糟的是,可能會導致至關重要的資料錯誤,例如金融交易或資料庫中唯一識別碼的處理。
記住:不要忽略精度限制。雖然這看起來像是一個小細節,但應用程式可能會以意想不到的方式失敗,而且代價高昂。
在 JavaScript 中,if 語句隱式會將表達式轉換為「真」或「假」值,如果不考慮此行為,可能會導致意外結果。儘管這種行為有時很有用,但建議在比較中明確,以避免細微的錯誤並提高程式碼的可讀性。
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 中虛假值的隱式行為。
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中文網其他相關文章!