在这篇文章中我将带你了解 JavaScript 编码时的“好习惯”。
1 — 避免使用 new Object()
在 JavaScript 中,使用 new Object 有点冒险,而使用原语总是更好,原因有几个。让我们深入探讨一下。
一般来说
例如,众所周知,“”创建一个字符串原语,另一方面…… new String() 创建一个字符串对象。由于它们更复杂并且具有方法,字符串对象可能会带来意想不到的行为,尤其是在比较和类型强制方面。
简单
原语的使用更简单、更直接,因为它们的使用避免了不必要的复杂性,并且代码变得易于阅读和维护。
性能
基元在内存和性能方面更加高效。创建对象时会涉及额外的开销。
可能的混乱
由于 JavaScript 对待对象和基元的方式不同,因此使用 new Object() 可能会导致令人困惑的情况,即您无意中处理的是对象而不是基元,这可能会导致大量错误。
在大多数情况下,最好使用原语。
// ❌ Avoid const str = new String(); const num = new Number(); const bool = new Boolean(); const obj = new Object(); const arr = new Array(); const regEx = new RegExp(); const func = new Function(); // ✅ Use const str = "JavaScript"; const num = 10; const bool = true; const obj = {}; const arr = []; const regEx = /()/; const func = function() {};
2 — 避免将 let 与数组和对象一起使用
首先,让我们明确一点……将 let 与数组和对象一起使用本质上根本没有问题。但有一些具体的考虑因素可能会导致您在某些情况下避免使用它:
重新分配与重新分配突变
众所周知,let 允许我们重新分配变量本身,这可能会导致混乱或数据丢失。对象/数组可能会意外地使用全新的数据集(新对象/新数组)重新分配。
使用 const 可以更安全、更清楚地表明对对象/数组的引用不会改变,但你仍然可以修改它的内容。
不变性意图
使用 const,您可以向与您一起工作的其他开发人员发出信号,表明不应重新分配该变量,从而增强代码的可读性和可维护性。
范围
虽然 let 具有块作用域,但它可能会导致循环或条件语句中出现意外行为。通过使用 const,变量保留在作用域内,而不会存在意外重新分配的风险。
最佳实践
许多编码标准和最佳实践鼓励对不需要重新分配的变量使用 const,从而促进更干净、更可预测的代码。
// ❌ Avoid let book = { title: "Inferno", author: "Dan Brown" }; // The book object will be overrode with string book = "Hello world"; // ✅ Use const book = { title: "Inferno", author: "Dan Brown" }; // The book object cannot be overrode book = "Hello world";
3 — 小心自动类型转换
在 JavaScript 中,也称为类型强制,当语言自动将值从一种类型转换为另一种类型时就会发生。这种情况可能会在各种情况下发生,尤其是在涉及不同数据类型的操作期间:
// ❌ Avoid const str = new String(); const num = new Number(); const bool = new Boolean(); const obj = new Object(); const arr = new Array(); const regEx = new RegExp(); const func = new Function(); // ✅ Use const str = "JavaScript"; const num = 10; const bool = true; const obj = {}; const arr = []; const regEx = /()/; const func = function() {};
小心数字,可能会意外转换为字符串或 NaN。因此,请考虑在敏感操作之前实施类型测试或考虑使用 TypeScript 进行安全输入。
4 — 避免使用双重相等比较
== 和 === 是用于比较值的比较运算符,但它们的行为不同。
抽象平等
使用 == 时,JavaScript 在进行比较之前会将值转换为通用类型
// ❌ Avoid let book = { title: "Inferno", author: "Dan Brown" }; // The book object will be overrode with string book = "Hello world"; // ✅ Use const book = { title: "Inferno", author: "Dan Brown" }; // The book object cannot be overrode book = "Hello world";
何时使用?
当您想确保值和类型相同时,请使用 ===,这通常是避免意外结果的好习惯。
如果您特别需要比较值而不考虑它们的类型,请使用 ==,但这可能会导致错误,并且通常不鼓励。
一般来说,考虑使用===来进行更可预测和更清晰的比较。
注意:同样的事情也适用于 !== 和 !=
5 — 使用对象/数组解构
在 JavaScript 中,使用对象和数组的解构技术可以给您带来很多好处。
解构赋值语法是一种 JavaScript 表达式,可以将数组中的值或对象中的属性解压到不同的变量中。正如 MDN 网络文档所述。
简洁
它允许您在一条语句中从对象中提取多个属性或从数组中提取元素,从而减少需要编写的代码量。
let sum = "5" + 1; // "51" (string concatenation) // In the code above, typeof sum is a string let sub = "5" - 1; // 4 (string converted to number) // In the code obove, typeof sub in a number Another example can be helpful: let lang = "JavaScript"; // typeof name is string lang = 15; // changes typeof x to a number
清晰度
解构可以通过清楚地显示您正在使用的属性或元素来使您的代码更具可读性。
console.log(5 == '5'); // true (number is converted to string) console.log(null == undefined); // true (considered equal) console.log(0 == false); // true (0 is converted to boolean as it's falsy value) Strict Equality With ===, the comparison checks both the value and the type. If types are different, it returns false console.log(5 === '5'); // false (different types) console.log(null === undefined); // false (different types) console.log(0 === false); // false (different types)
默认值
如果属性或元素不存在,您可以轻松分配默认值。
const book = { name: 'The Lost Symbol', author: 'Dan Brown' }; const { name, price } = book; // concise extraction
嵌套解构
您可以解构嵌套对象或数组,这可以简化对深层嵌套数据的访问。
const colors = ['red', 'green', 'blue']; const [firstColor, secondColor] = colors; // clear intention
函数参数
它对于函数参数很有用,允许您直接解压值。
const { height = 180 } = person; // uses default value if height is undefined
解构有助于简化代码,使其更干净且更易于维护。
6 — 默认参数
默认参数是一种很好的技术,可以让你的代码更清晰、易于阅读。
默认函数参数允许在没有传递值或未定义的情况下使用默认值初始化命名参数。正如 MDN 网络文档所述。
单个参数
const user = { profile: { name: 'Eren Yeager', age: 20 } }; const { profile: { name } } = user; // easy access to nested properties
多个参数
您可以为多个参数设置默认值。
function display({ name, age }) { console.log(`${name} is ${age} years old.`); }
传递多个参数时请注意未给定的参数。避免将可能未定义或可能未传递的参数作为第一个参数或在任何其他传递的参数之前传递。
如果您怀疑某个参数值可能未给出或可能以未定义的形式传递,请确保将其作为最后一个传递,以及多个未给定的参数。
使用表达式作为默认值
您可以使用表达式来计算默认值。
// ❌ Avoid const str = new String(); const num = new Number(); const bool = new Boolean(); const obj = new Object(); const arr = new Array(); const regEx = new RegExp(); const func = new Function(); // ✅ Use const str = "JavaScript"; const num = 10; const bool = true; const obj = {}; const arr = []; const regEx = /()/; const func = function() {};
使用默认值的其余参数
您可以将默认参数与其余参数结合起来。
// ❌ Avoid let book = { title: "Inferno", author: "Dan Brown" }; // The book object will be overrode with string book = "Hello world"; // ✅ Use const book = { title: "Inferno", author: "Dan Brown" }; // The book object cannot be overrode book = "Hello world";
好处
提高可读性:如果省略参数,则使用默认值是很清楚的。
更少的样板:减少在函数体内检查和分配默认值的需要。
增强的灵活性:函数可以更优雅地处理更广泛的输入。
默认参数是一个强大的功能,可以增强函数可用性并使您的代码更干净!
7 — 在开关中使用默认值
在 JavaScript 中,以 default case 结束 switch 语句是一个很好的做法。当指定的情况都不与输入匹配时,默认情况将充当后备:
let sum = "5" + 1; // "51" (string concatenation) // In the code above, typeof sum is a string let sub = "5" - 1; // 4 (string converted to number) // In the code obove, typeof sub in a number Another example can be helpful: let lang = "JavaScript"; // typeof name is string lang = 15; // changes typeof x to a number
包罗万象
它提供了一种处理意外值的方法,确保您的代码不会默默地失败。
console.log(5 == '5'); // true (number is converted to string) console.log(null == undefined); // true (considered equal) console.log(0 == false); // true (0 is converted to boolean as it's falsy value) Strict Equality With ===, the comparison checks both the value and the type. If types are different, it returns false console.log(5 === '5'); // false (different types) console.log(null === undefined); // false (different types) console.log(0 === false); // false (different types)
提高可读性
包含默认情况可以让其他开发人员(或您自己)清楚地知道您考虑了所有可能性。
错误处理
它可用于在遇到意外值时记录或抛出错误。
const book = { name: 'The Lost Symbol', author: 'Dan Brown' }; const { name, price } = book; // concise extraction
如果有可能收到意外输入,请始终包含默认情况。
使用默认情况提供有用的反馈或日志记录,尤其是在调试场景中。
如果适用,请考虑使用默认情况来设置后备值。
在 switch 语句中添加 default case 可以增强代码的稳健性和可维护性。
8 — 避免使用 eval()
eval() 是一个内置 JavaScript 函数,它将字符串作为参数并将其计算为 JavaScript 代码。这意味着您可以动态执行在运行时生成的代码。
const colors = ['red', 'green', 'blue']; const [firstColor, secondColor] = colors; // clear intention
由于几个重要原因,广泛建议避免在 JavaScript 中使用 eval()。
安全风险
代码注入:eval() 可以执行任意代码,使您的应用程序容易受到代码注入攻击。如果评估用户输入,攻击者可能会注入恶意代码。
const { height = 180 } = person; // uses default value if height is undefined
性能问题
执行缓慢:使用 eval() 执行的代码运行速度比常规代码慢,因为它必须在运行时解释,绕过 JavaScript 引擎所做的某些优化。
调试挑战
更难调试:使用 eval() 会使调试变得困难。 eval() 内部抛出的错误可能很难追溯到原始来源。
替代方案
考虑这些更安全的替代方案,而不是 eval():
JSON 解析:如果您正在处理 JSON 数据,请使用 JSON.parse() 而不是 eval()。
const jsonString = '{"name": "Alice"}';
const obj = JSON.parse(jsonString); // 将 JSON 字符串转换为对象的安全方法
函数构造函数:如果您需要动态创建函数,请考虑使用函数构造函数。
// ❌ Avoid const str = new String(); const num = new Number(); const bool = new Boolean(); const obj = new Object(); const arr = new Array(); const regEx = new RegExp(); const func = new Function(); // ✅ Use const str = "JavaScript"; const num = 10; const bool = true; const obj = {}; const arr = []; const regEx = /()/; const func = function() {};
总之,由于安全风险、性能问题和调试困难,请避免使用 eval()。选择更安全的替代方案来实现您的目标,而不会影响代码的完整性和性能。
9 — 使用严格模式
在 JavaScript 中,“严格模式”是一种选择该语言的受限制变体的方法,有助于捕获常见的编码错误和“不安全”操作。它可以使您的代码更可预测且更易于调试。
启用严格模式
全局:通过设置“use strict”;位于脚本文件的顶部。
// ❌ Avoid let book = { title: "Inferno", author: "Dan Brown" }; // The book object will be overrode with string book = "Hello world"; // ✅ Use const book = { title: "Inferno", author: "Dan Brown" }; // The book object cannot be overrode book = "Hello world";
使用严格模式的好处
防止使用未声明的变量:为未声明的变量赋值会引发错误。
let sum = "5" + 1; // "51" (string concatenation) // In the code above, typeof sum is a string let sub = "5" - 1; // 4 (string converted to number) // In the code obove, typeof sub in a number Another example can be helpful: let lang = "JavaScript"; // typeof name is string lang = 15; // changes typeof x to a number
消除了这种强制:在严格模式下,在没有显式上下文的情况下调用的函数中这是未定义的。
console.log(5 == '5'); // true (number is converted to string) console.log(null == undefined); // true (considered equal) console.log(0 == false); // true (0 is converted to boolean as it's falsy value) Strict Equality With ===, the comparison checks both the value and the type. If types are different, it returns false console.log(5 === '5'); // false (different types) console.log(null === undefined); // false (different types) console.log(0 === false); // false (different types)
禁止某些语法:不允许某些被认为有问题或令人困惑的语法。
常见陷阱
箭头函数:请注意,箭头函数没有自己的 this,因此严格模式不适用于相同的方式。
eval:eval 语句中执行的代码在本地作用域而不是全局作用域中运行。
使用严格模式通常被认为是最佳实践,尤其是对于大型应用程序,因为它可以帮助您编写更干净、更安全的代码。
10 — 保持代码干燥(不要重复)
DRY(不要重复自己)原则是软件开发中的一个关键概念,旨在减少代码重复。通过确保每条知识或逻辑都在一个位置表示,您可以使代码更易于维护、理解和重构。
功能
将重复的逻辑封装在函数中。这样,您就可以重复使用相同的代码。
const book = { name: 'The Lost Symbol', author: 'Dan Brown' }; const { name, price } = book; // concise extraction
模块
使用模块来组织您的代码。这有助于将相关的函数和变量放在一起,使它们可以在应用程序的不同部分中重用。
const colors = ['red', 'green', 'blue']; const [firstColor, secondColor] = colors; // clear intention
类和对象
利用类或对象对相关数据和行为进行分组。这种封装有助于避免在使用类似的数据结构时出现重复。
const { height = 180 } = person; // uses default value if height is undefined
注意:如果您在日常编码中采用“函数式编程”范例,请考虑使用除“类和对象”之外的任何其他技巧。
模板和组件
在Web开发中,使用模板或组件(在React、Vue等框架中)来封装重复使用的UI逻辑和样式。
// ❌ Avoid const str = new String(); const num = new Number(); const bool = new Boolean(); const obj = new Object(); const arr = new Array(); const regEx = new RegExp(); const func = new Function(); // ✅ Use const str = "JavaScript"; const num = 10; const bool = true; const obj = {}; const arr = []; const regEx = /()/; const func = function() {};
数据结构
使用数组或对象来存储相关数据,而不是为每条数据创建单独的变量。
// ❌ Avoid let book = { title: "Inferno", author: "Dan Brown" }; // The book object will be overrode with string book = "Hello world"; // ✅ Use const book = { title: "Inferno", author: "Dan Brown" }; // The book object cannot be overrode book = "Hello world";
应用 DRY 原则可以生成更干净、更易于维护的代码。它有助于最大限度地降低错误风险,因为只需在一个地方进行更改,并且通过减少混乱来增强可读性。请记住,虽然避免重复很重要,但也需要保持平衡;过度抽象可能会导致复杂性,因此在应用这些原则时请运用您的判断。
11 — 使用有意义的变量和函数名称
使用有意义的变量和函数名称对于编写清晰、可维护和易于理解的代码至关重要。
具有描述性
选择能够清楚描述变量或函数的用途或值的名称。
let sum = "5" + 1; // "51" (string concatenation) // In the code above, typeof sum is a string let sub = "5" - 1; // 4 (string converted to number) // In the code obove, typeof sub in a number Another example can be helpful: let lang = "JavaScript"; // typeof name is string lang = 15; // changes typeof x to a number
使用功能动作词
用描述正在执行的操作的动词开始函数。
console.log(5 == '5'); // true (number is converted to string) console.log(null == undefined); // true (considered equal) console.log(0 == false); // true (0 is converted to boolean as it's falsy value) Strict Equality With ===, the comparison checks both the value and the type. If types are different, it returns false console.log(5 === '5'); // false (different types) console.log(null === undefined); // false (different types) console.log(0 === false); // false (different types)
避免缩写
虽然短名称看起来很方便,但它们可能会导致混乱。避免使用缩写,除非它们被广泛理解。
const book = { name: 'The Lost Symbol', author: 'Dan Brown' }; const { name, price } = book; // concise extraction
使用一致的命名约定
在整个代码库中坚持一致的命名约定,例如变量和函数的驼峰命名法以及类的帕斯卡命名法。
const colors = ['red', 'green', 'blue']; const [firstColor, secondColor] = colors; // clear intention
在名称中指明数据类型或用途
如果变量保存特定类型的数据或用于特定目的,请将其包含在名称中。
const { height = 180 } = person; // uses default value if height is undefined
使用上下文信息
考虑使用变量或函数的上下文以使名称更有意义。
const user = { profile: { name: 'Eren Yeager', age: 20 } }; const { profile: { name } } = user; // easy access to nested properties
保持简洁但清晰
虽然名称应该具有描述性,但名称不应该太长。力求在清晰和简洁之间取得平衡。
function display({ name, age }) { console.log(`${name} is ${age} years old.`); }
使用特定领域的语言
如果您在特定领域(例如金融、医疗保健等)工作,请使用该领域熟悉的术语。
令利率 = 5.5; // 在金融背景下清晰。
function greet(name = 'Guest') { console.log(`Hello, ${name}!`); } greet(); // Output: Hello, Guest! greet('Chrollo'); // Output: Hello, Chrollo!
必要时重构
如果您发现随着代码的发展,某个名称不再合适,请毫不犹豫地重构它以使其更加清晰。
function multiply(a, b = 1) { return a * b; } multiply(5); // Output: 5 multiply(5, 2); // Output: 10
有意义的变量和函数名称显着增强代码的可读性和可维护性。它们可以帮助其他人(和您自己)一目了然地了解代码的目的和功能,从而使协作和调试变得更加容易。始终力求命名约定清晰。
12 — 避免全局变量
避免全局变量是 JavaScript(以及一般编程)中维护干净、模块化和可维护代码的关键实践。全局变量可能会导致意外行为、命名冲突和调试困难。
使用函数作用域
在函数内声明变量以限制其范围并防止它们被全局访问。
// ❌ Avoid const str = new String(); const num = new Number(); const bool = new Boolean(); const obj = new Object(); const arr = new Array(); const regEx = new RegExp(); const func = new Function(); // ✅ Use const str = "JavaScript"; const num = 10; const bool = true; const obj = {}; const arr = []; const regEx = /()/; const func = function() {};
通过 let 和 const 使用块作用域
使用 let 和 const 在块内声明变量(如循环或条件),确保它们在块外不可访问。
// ❌ Avoid let book = { title: "Inferno", author: "Dan Brown" }; // The book object will be overrode with string book = "Hello world"; // ✅ Use const book = { title: "Inferno", author: "Dan Brown" }; // The book object cannot be overrode book = "Hello world";
模块化您的代码
将您的代码组织成模块。使用ES6模块或IIFE(立即调用函数表达式)来封装变量。
let sum = "5" + 1; // "51" (string concatenation) // In the code above, typeof sum is a string let sub = "5" - 1; // 4 (string converted to number) // In the code obove, typeof sub in a number Another example can be helpful: let lang = "JavaScript"; // typeof name is string lang = 15; // changes typeof x to a number
封装在对象中:
将相关变量和函数分组到一个对象内,以避免污染全局范围。
console.log(5 == '5'); // true (number is converted to string) console.log(null == undefined); // true (considered equal) console.log(0 == false); // true (0 is converted to boolean as it's falsy value) Strict Equality With ===, the comparison checks both the value and the type. If types are different, it returns false console.log(5 === '5'); // false (different types) console.log(null === undefined); // false (different types) console.log(0 === false); // false (different types)
明智地使用本地存储
如果需要持久化数据,请考虑使用本地存储、会话存储或indexedDB,而不是全局变量。
const book = { name: 'The Lost Symbol', author: 'Dan Brown' }; const { name, price } = book; // concise extraction
限制全局变量的使用
如果必须使用全局变量,请将其使用限制为配置常量或应用程序范围的设置。清楚地命名它们以表明它们的全球性。
const colors = ['red', 'green', 'blue']; const [firstColor, secondColor] = colors; // clear intention
避免副作用
设计函数时,避免修改全局变量。这使得函数可预测并且更容易测试。
const { height = 180 } = person; // uses default value if height is undefined
明智地使用“这个”
在面向对象编程中,使用它来管理实例内的状态,而不是依赖全局变量。
const user = { profile: { name: 'Eren Yeager', age: 20 } }; const { profile: { name } } = user; // easy access to nested properties
通过避免全局变量,您可以增强代码的模块化和可维护性。它有助于防止命名冲突和意外的副作用,使您的代码更可预测且更易于使用。遵循这些最佳实践将带来更干净、更易于管理的代码库。
13 — 使用 Promises 和 Async/Await 实现异步代码
在 JavaScript 中使用 Promises 和 async/await 有助于更有效地管理异步操作,使您的代码更干净、更易于阅读。
理解承诺
Promise 是一个对象,表示异步操作的最终完成(或失败)及其结果值。
您可以使用 Promise 构造函数创建 Promise:
function display({ name, age }) { console.log(`${name} is ${age} years old.`); }
消费承诺
您可以使用 .then() 来处理 Promise 的结果以获取成功,使用 .catch() 来处理错误。
function greet(name = 'Guest') { console.log(`Hello, ${name}!`); } greet(); // Output: Hello, Guest! greet('Chrollo'); // Output: Hello, Chrollo!
连锁承诺
您可以使用 Promises 链接多个异步操作。
function multiply(a, b = 1) { return a * b; } multiply(5); // Output: 5 multiply(5, 2); // Output: 10
使用异步/等待
async/await 提供了一种更加同步的方式来编写异步代码,使其更易于阅读和维护。
声明异步函数:
在函数前使用 async 关键字将其定义为异步函数。
// ❌ Avoid const str = new String(); const num = new Number(); const bool = new Boolean(); const obj = new Object(); const arr = new Array(); const regEx = new RegExp(); const func = new Function(); // ✅ Use const str = "JavaScript"; const num = 10; const bool = true; const obj = {}; const arr = []; const regEx = /()/; const func = function() {};
调用异步函数
您可以像调用常规函数一样调用异步函数。但是,请注意它总是会返回一个 Promise。
// ❌ Avoid let book = { title: "Inferno", author: "Dan Brown" }; // The book object will be overrode with string book = "Hello world"; // ✅ Use const book = { title: "Inferno", author: "Dan Brown" }; // The book object cannot be overrode book = "Hello world";
处理多个异步操作
您可以使用 Promise.all 并行运行多个 Promise 并等待它们全部解析。
let sum = "5" + 1; // "51" (string concatenation) // In the code above, typeof sum is a string let sub = "5" - 1; // 4 (string converted to number) // In the code obove, typeof sub in a number Another example can be helpful: let lang = "JavaScript"; // typeof name is string lang = 15; // changes typeof x to a number
错误处理
Promises 和 async/await 都提供了优雅地处理错误的方法。
将 .catch() 与 Promise 一起使用:
console.log(5 == '5'); // true (number is converted to string) console.log(null == undefined); // true (considered equal) console.log(0 == false); // true (0 is converted to boolean as it's falsy value) Strict Equality With ===, the comparison checks both the value and the type. If types are different, it returns false console.log(5 === '5'); // false (different types) console.log(null === undefined); // false (different types) console.log(0 === false); // false (different types)
将 try/catch 与 Async/Await 结合使用:
const book = { name: 'The Lost Symbol', author: 'Dan Brown' }; const { name, price } = book; // concise extraction
使用 Promises 和 async/await 使得在 JavaScript 中处理异步操作变得更加易于管理。它们有助于避免回调地狱并提高代码可读性。拥抱这些模式将带来更干净、更易于维护且防错的代码。
14 — 记录您的代码
记录代码对于保持清晰度、帮助协作和确保长期可维护性至关重要。
使用清晰的评论
解释“为什么”,而不是“什么”:重点解释为什么你做了某件事,而不是代码做了什么。代码本身应该具有足够的可读性来传达它的作用。
const colors = ['red', 'green', 'blue']; const [firstColor, secondColor] = colors; // clear intention
注释复杂逻辑:对于复杂或不明显的代码部分,提供详细的解释。
const { height = 180 } = person; // uses default value if height is undefined
使用文档字符串样式注释
在 JavaScript 中,尤其是使用 JSDoc 时,您可以使用结构化注释来记录函数、类和方法。
const user = { profile: { name: 'Eren Yeager', age: 20 } }; const { profile: { name } } = user; // easy access to nested properties
维护自述文件
对于项目,维护一个 README.md 文件,其中提供概述、安装说明、使用示例和贡献指南。
有效的文档使您的代码更易于理解和维护,帮助当前和未来的开发人员(包括您自己)高效工作。通过将这些实践纳入您的开发工作流程,您将促进更好的协作并缩短与您的代码交互的任何人的学习曲线。
以上是JavaScript 最佳实践的详细内容。更多信息请关注PHP中文网其他相关文章!