JavaScript 最佳实践
JavaScript 最佳实践
Section titled “JavaScript 最佳实践”编写清晰、高效、易于维护的 JavaScript 代码需要遵循一些最佳实践。这些实践包括管理作用域(scope)、使用现代变量声明方式、正确处理类型以及采用安全的编码模式。
最小化全局变量:使用模块和局部作用域
Section titled “最小化全局变量:使用模块和局部作用域”过度使用全局变量(global variables)可能导致命名冲突,并使代码更难管理和调试。在一个脚本中声明的全局变量可能会被另一个脚本意外覆盖。
现代 JavaScript 推崇使用 ES 模块(ES Modules,import/export 语法)来封装代码和管理依赖。这自然地限制了全局作用域(global scope)。
在函数或代码块(block)内,始终使用 let 或 const 声明变量,以使它们具有局部作用域(locally scoped)。
使用 let 和 const 声明变量
Section titled “使用 let 和 const 声明变量”在现代 JavaScript 中,避免使用 var 关键字声明变量。相反,对于可能重新赋值的变量使用 let,对于声明后不应重新赋值的变量(常量)使用 const。
let 和 const 是块级作用域(block-scoped)的,这意味着它们只能在声明它们的代码块(由 { } 定义)内部访问。这有助于防止变量意外泄露并提高代码清晰度。
// Example of block scopeif (true) { const blockScopedVar = "I'm block-scoped"; let anotherBlockVar = 10; // console.log(blockScopedVar, anotherBlockVar); // Accessible here}// console.log(blockScopedVar); // Error: blockScopedVar is not defined here在脚本或模块的开头使用 "use strict"; 有助于捕获常见的编码错误,例如使用未声明的变量。请注意,ES 模块默认处于严格模式(strict mode)。
在使用前声明并初始化变量
Section titled “在使用前声明并初始化变量”在变量使用前声明它们是一个好的习惯,通常是在它们作用域(函数或块)的开头进行。
在声明变量时进行初始化可以防止 undefined 值引起的意外行为,并使预期的数据类型更清晰。
这提高了代码的可读性,并有助于避免以下错误:
- 更清晰的代码结构。
- 在同一作用域内只需查找一个地方即可找到变量声明。
- 避免了在使用变量前进行赋值相关的错误。
// Declare and initialize at the beginning of their scopefunction processOrder(items) { const taxRate = 0.08; let subTotal = 0; let customerName = "Guest";
// ... rest of the function logic}
for (let i = 0; i < 5; i++) { // loop logic using i}虽然 JavaScript 会提升(hoists)声明,但 let 和 const 有一个“暂时性死区”(Temporal Dead Zone,TDZ),这意味着在代码中声明之前,你无法访问它们。这通常是一件好事,因为它阻止了使用未初始化的变量。 |
|---|
直接使用原始值;避免对象包装器
Section titled “直接使用原始值;避免对象包装器”始终将数字(numbers)、字符串(strings)和布尔值(booleans)视为原始值(primitive values)。避免使用 new Number()、new String() 或 new Boolean() 将它们创建为对象(objects)。
使用对象包装器会降低执行速度,并可能导致令人困惑的行为,尤其是在比较时:
const primitiveString = "John";const objectString = new String("John");
console.log(typeof primitiveString); // "string"console.log(typeof objectString); // "object"
console.log(primitiveString === "John"); // trueconsole.log(objectString === "John"); // false (object vs string)console.log(primitiveString === objectString); // falseconsole.log(new String("John") === new String("John")); // false (different objects)对对象、数组和函数使用字面量
Section titled “对对象、数组和函数使用字面量”优先使用字面量(literal)语法来创建对象、数组、正则表达式和函数,而不是使用它们对应的构造函数:
- 使用
{}而不是new Object() - 使用
""(或''、`)而不是new String() - 使用
0而不是new Number() - 使用
false(或true)而不是new Boolean() - 使用
[]而不是new Array() - 使用
/()/而不是new RegExp() - 使用
function() {}或() => {}而不是new Function()
const myObject = {}; // Preferred object literalconst myString = ""; // Preferred string literalconst myNumber = 0; // Preferred number literalconst myBoolean = false; // Preferred boolean literalconst myArray = []; // Preferred array literalconst myRegExp = /abc/g; // Preferred RegExp literalconst myFunction = () => {}; // Preferred function expression (arrow function)警惕自动类型转换;使用严格相等比较
Section titled “警惕自动类型转换;使用严格相等比较”JavaScript 是弱类型(loosely typed)的,这意味着变量可以改变类型,并且在操作过程中会发生自动类型转换(coercion)。这有时可能导致意外的结果。
let value = "Hello"; // typeof value is "string"value = 5; // typeof value is now "number"比较值时,宽松相等运算符(==)会执行类型转换,而严格相等运算符(===)则不会。通常来说,使用严格相等(===)和严格不等(!==)更安全、更可预测。
console.log(0 == ""); // true (string "" coerces to 0)console.log(0 === ""); // false (number vs string)
console.log(1 == "1"); // true (string "1" coerces to 1)console.log(1 === "1"); // false (number vs string)
console.log(null == undefined); // true (special case for loose equality)console.log(null === undefined);// false使用 ES6 默认参数
Section titled “使用 ES6 默认参数”如果调用函数时提供的参数少于声明的参数,则缺失的参数将具有 undefined 值。现代 JavaScript(ES6+)允许你在函数签名中直接为函数参数定义默认值(default values)。
这比手动检查 undefined 并赋值默认值更简洁、更具表达力。
// Modern ES6+ way with default parametersfunction greet(name = "Guest", greeting = "Hello") { console.log(`${greeting}, ${name}!`);}
greet("Alice"); // Output: Hello, Alice!greet(); // Output: Hello, Guest!在相关的 JavaScript 函数章节中了解更多关于函数参数和参数的信息。
在 switch 语句结尾包含 default 情况
Section titled “在 switch 语句结尾包含 default 情况”在 switch 语句中始终包含一个 default 情况是一个好的实践,即使你认为所有可能的情况都已涵盖。这可以优雅地处理意外的值,并使你的代码更健壮。
let dayName;switch (new Date().getDay()) { case 0: dayName = "Sunday"; break; case 1: dayName = "Monday"; break; // ... other cases case 6: dayName = "Saturday"; break; default: dayName = "Unknown Day"; // Handles unexpected values // console.error("Unexpected day value");}避免使用 eval()
Section titled “避免使用 eval()”eval() 函数执行一个字符串作为 JavaScript 代码。强烈不建议使用它,因为它存在重大的安全风险(如果字符串来自不可信来源,它可能执行恶意代码)和性能影响。
几乎总是有比 eval() 更安全、更有效的替代方法。解析 JSON 时,使用 JSON.parse()。对于动态属性访问,使用方括号表示法(object[propertyName])。