JavaScript 的核心设计理念是灵活性和表达力。多年来,随着 ECMAScript 标准(ES6、ES2015 及更高版本)的不断发展,该语言引入了大量语法糖和强大的功能,可以显著简化您的代码。
了解这些技巧不仅能减少代码量,还能写出更简洁、更易读、通常也更高效的代码。掌握这些技巧可以将你的 JavaScript 技能从熟练提升到真正的大师级。
现在让我们深入了解 25 个现代 JavaScript 技巧,它们将彻底改变你的工作效率!
1. 三元运算符:简洁的条件语句
用一行代码即可轻松替换冗长的 if/else 语句,从而简化简单的条件语句。
// Before
let age = 18;
let canVote;
if (age >= 18) {
canVote = "Yes";
} else {
canVote = "No";
}
console.log(canVote); // Output: Yes
// After
let age = 18;
let canVote = (age >= 18) ? "Yes" : "No";
console.log(canVote); // Output: Yes
2. 默认值短路 (||)
如果第一个操作数为假值 (null、undefined、0、""、false),则使用逻辑或运算符分配默认值。
// Before
function greet(name) {
let displayName;
if (name === null || name === undefined || name === "") {
displayName = "Guest";
} else {
displayName = name;
}
console.log(`Hello, ${displayName}!`);
}
greet("Alice"); // Output: Hello, Alice!
greet(null); // Output: Hello, Guest!
// After
function greet(name) {
const displayName = name || "Guest";
console.log(`Hello, ${displayName}!`);
}
greet("Alice"); // Output: Hello, Alice!
greet(null); // Output: Hello, Guest!
greet(""); // Output: Hello, Guest!
3. 条件执行的短路 (&&)
使用逻辑“与”运算符,仅当条件为真时才执行代码。
// Before
let isAdmin = true;
if (isAdmin) {
console.log("Admin privileges granted.");
}
// After
let isAdmin = true;
isAdmin && console.log("Admin privileges granted."); // Output: Admin privileges granted.
let isGuest = false;
isGuest && console.log("Guest access."); // No output
4. 模板字面量:简单的字符串插值
使用反引号 ` 将表达式直接嵌入字符串字面量中。
// Before
const name = "Bob";
const age = 30;
console.log("My name is " + name + " and I am " + age + " years old.");
// After
const name = "Bob";
const age = 30;
console.log(`My name is ${name} and I am ${age} years old.`); // Output: My name is Bob and I am 30 years old.
5. 箭头函数:更简洁的语法和 this 绑定
一种更简洁的函数表达式编写方式,尤其适用于回调函数。它们也实现了 this 的词法绑定。
// Before
const numbers = [1, 2, 3];
const doubled = numbers.map(function(num) {
return num * 2;
});
console.log(doubled); // Output: [2, 4, 6]
// After
const numbers = [1, 2, 3];
const doubled = numbers.map(num => num * 2); // Implicit return for single expression
console.log(doubled); // Output: [2, 4, 6]
// 'this' binding difference
function Counter() {
this.count = 0;
// 'this' inside function() is window/undefined
setInterval(function() {
// console.log(this.count); // Error or undefined
}, 1000);
// 'this' inside arrow function refers to Counter instance
setInterval(() => {
this.count++;
// console.log(this.count); // Correctly increments
}, 1000);
}
// new Counter();
6. 解构赋值(数组):提取值
将数组中的值解包到不同的变量中。
// Before
const colors = ["red", "green", "blue"];
const firstColor = colors[0];
const secondColor = colors[1];
console.log(firstColor, secondColor); // Output: red green
// After
const colors = ["red", "green", "blue"];
const [firstColor, secondColor] = colors;
console.log(firstColor, secondColor); // Output: red green
// Skip values
const [,,thirdColor] = colors;
console.log(thirdColor); // Output: blue
7. 解构赋值(对象):提取属性
将对象的属性解包到不同的变量中。
// Before
const user = { name: "Charlie", age: 25 };
const userName = user.name;
const userAge = user.age;
console.log(userName, userAge); // Output: Charlie 25
// After
const user = { name: "Charlie", age: 25, city: "NYC" };
const { name, age } = user;
console.log(name, age); // Output: Charlie 25
// With alias
const { name: fullName, city } = user;
console.log(fullName, city); // Output: Charlie NYC
8. 扩展语法(数组):复制和连接
轻松创建数组的浅拷贝或连接数组。
// Before
const arr1 = [1, 2];
const arr2 = [3, 4];
const copiedArr = arr1.slice();
const combinedArr = arr1.concat(arr2);
console.log(copiedArr, combinedArr); // Output: [1, 2] [1, 2, 3, 4]
// After
const arr1 = [1, 2];
const arr2 = [3, 4];
const copiedArr = [...arr1];
const combinedArr = [...arr1, ...arr2];
console.log(copiedArr, combinedArr); // Output: [1, 2] [1, 2, 3, 4]
9. 扩展语法(对象):复制与合并
创建对象的浅拷贝或合并对象。
// Before
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const copiedObj = Object.assign({}, obj1);
const mergedObj = Object.assign({}, obj1, obj2);
console.log(copiedObj, mergedObj); // Output: { a: 1, b: 2 } { a: 1, b: 2, c: 3, d: 4 }
// After
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const copiedObj = { ...obj1 };
const mergedObj = { ...obj1, ...obj2 };
console.log(copiedObj, mergedObj); // Output: { a: 1, b: 2 } { a: 1, b: 2, c: 3, d: 4 }
// Overriding properties
const original = { x: 1, y: 2 };
const updated = { ...original, y: 3, z: 4 };
console.log(updated); // Output: { x: 1, y: 3, z: 4 }
10. 剩余参数:收集参数
将不定数量的参数收集到一个数组中。
// Before
function sumAll() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(sumAll(1, 2, 3, 4)); // Output: 10
// After
function sumAll(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sumAll(1, 2, 3, 4, 5)); // Output: 15
11. 默认参数:设置参数默认值
如果函数参数未定义或未提供,则提供默认值。
// Before
function greet(name, greeting) {
name = name || "Guest";
greeting = greeting || "Hello";
console.log(`${greeting}, ${name}!`);
}
greet(); // Output: Hello, Guest!
greet("Eve"); // Output: Hello, Eve!
// After
function greet(name = "Guest", greeting = "Hello") {
console.log(`${greeting}, ${name}!`);
}
greet(); // Output: Hello, Guest!
greet("Frank"); // Output: Hello, Frank!
greet("Grace", "Hi"); // Output: Hi, Grace!
12. 可选链式调用 (?.):安全访问嵌套属性
访问可能为 null 或 undefined 的对象属性,而不会抛出错误。
// Before modification
const user = {
profile: {
address: {
street: "Main St"
}
}
};
let streetName;
if (user && user.profile && user.profile.address) {
streetName = user.profile.address.street;
}
console.log(streetName); // Output: Main St
const invalidUser = {};
let invalidStreet;
// This will throw an error: invalidUser.profile is undefined
// if (invalidUser && invalidUser.profile && invalidUser.profile.address) {
// invalidStreet = invalidUser.profile.address.street;
// }
console.log(invalidStreet); // Output: undefined
// After modification
const user = {
profile: {
address: {
street: "Main St"
}
}
};
const streetName = user.profile?.address?.street;
console.log(streetName); // Output: Main St
const invalidUser = {};
const invalidStreet = invalidUser.profile?.address?.street;
console.log(invalidStreet); // Output: undefined
13. 空值合并 (??):仅处理 null 或 undefined
类似于 ||,但仅当左操作数为 null 或 undefined(而不是 0 或 "")时才回退到默认值。
// Using || (logical OR)
const count = 0;
const defaultCount_OR = count || 10;
console.log(defaultCount_OR); // Output: 10 (incorrect if 0 is a valid value)
// Using ?? (nullish coalescing)
const count = 0;
const defaultCount_NC = count ?? 10;
console.log(defaultCount_NC); // Output: 0 (correct, 0 is not null/undefined)
const emptyString = "";
const defaultString_NC = emptyString ?? "Default";
console.log(defaultString_NC); // Output: "" (correct)
const undefinedValue = undefined;
const defaultValue_NC = undefinedValue ?? "Fallback";
console.log(defaultValue_NC); // Output: Fallback
14. forEach 用于迭代
一种简洁的迭代数组元素的方法,无需显式循环计数器。
// Before
const items = ["apple", "banana", "cherry"];
for (let i = 0; i < items.length; i++) {
console.log(items[i]);
}
// After
const items = ["apple", "banana", "cherry"];
items.forEach(item => console.log(item));
/*
Output:
apple
banana
cherry
*/
15. map 用于转换
通过将函数应用于现有数组的每个元素来创建新数组。
// Before
const numbers = [1, 2, 3];
const squaredNumbers = [];
for (let i = 0; i < numbers.length; i++) {
squaredNumbers.push(numbers[i] * numbers[i]);
}
console.log(squaredNumbers); // Output: [1, 4, 9]
// After
const numbers = [1, 2, 3];
const squaredNumbers = numbers.map(num => num * num);
console.log(squaredNumbers); // Output: [1, 4, 9]
16. filter 用于过滤
创建一个仅包含通过测试条件的元素的新数组。
// Before
const ages = [10, 20, 15, 30];
const adults = [];
for (let i = 0; i < ages.length; i++) {
if (ages[i] >= 18) {
adults.push(ages[i]);
}
}
console.log(adults); // Output: [20, 30]
// After
const ages = [10, 20, 15, 30];
const adults = ages.filter(age => age >= 18);
console.log(adults); // Output: [20, 30]
17. Reduce 聚合及更多
对累加器和数组中的每个元素(从左到右)应用函数,将其约简为单个值。适用于复杂的聚合操作。
// Before
const prices = [10, 20, 5];
let totalPrice = 0;
for (let i = 0; i < prices.length; i++) {
totalPrice += prices[i];
}
console.log(totalPrice); // Output: 35
// After (Summing)
const prices = [10, 20, 5];
const totalPrice = prices.reduce((sum, price) => sum + price, 0);
console.log(totalPrice); // Output: 35
// After (Flattening an array of arrays)
const nestedArrays = [[1, 2], [3, 4], [5]];
const flattened = nestedArrays.reduce((acc, current) => [...acc, ...current], []);
console.log(flattened); // Output: [1, 2, 3, 4, 5]
18. Object.keys()、Object.values()、Object.entries()
轻松迭代对象属性、值或键值对。
const car = {
make: "Toyota",
model: "Camry",
year: 2020
};
// Keys
console.log(Object.keys(car)); // Output: ["make", "model", "year"]
// Values
console.log(Object.values(car)); // Output: ["Toyota", "Camry", 2020]
// Entries (key-value pairs)
console.log(Object.entries(car));
/* Output:
[
["make", "Toyota"],
["model", "Camry"],
["year", 2020]
]
*/
// Iterating with forEach
Object.entries(car).forEach(([key, value]) => {
console.log(`${key}: ${value}`);
});
/* Output:
make: Toyota
model: Camry
year: 2020
*/
19. 箭头函数中的隐式返回
对于仅包含单个表达式的箭头函数,可以省略花括号 {} 和 return 关键字。
// Before
const add = (a, b) => {
return a + b;
};
console.log(add(5, 3)); // Output: 8
// After
const add = (a, b) => a + b;
console.log(add(5, 3)); // Output: 8
// For returning an object literal, wrap it in parentheses
const createUser = (name, age) => ({ name, age });
console.log(createUser("Dora", 28)); // Output: { name: 'Dora', age: 28 }
20. 类型转换为布尔值 (!!)
一种将任何值快速转换为其布尔值等效值的方法。
// Before
const value = "hello";
let isTruthy;
if (value) {
isTruthy = true;
} else {
isTruthy = false;
}
console.log(isTruthy); // Output: true
// After
const value1 = "hello";
const isTruthy1 = !!value1;
console.log(isTruthy1); // Output: true
const value2 = 0;
const isTruthy2 = !!value2;
console.log(isTruthy2); // Output: false
const value3 = null;
const isTruthy3 = !!value3;
console.log(isTruthy3); // Output: false
21. 类型转换为数字 (+)
一种将表示数字的字符串快速转换为实际数字的方法。
// Before
const numStr = "123";
const num = parseInt(numStr, 10);
console.log(num, typeof num); // Output: 123 'number'
// After
const numStr = "123";
const num = +numStr;
console.log(num, typeof num); // Output: 123 'number'
const floatStr = "123.45";
const floatNum = +floatStr;
console.log(floatNum, typeof floatNum); // Output: 123.45 'number'
22. 快速对象属性赋值(简写属性)
当变量名与要赋给对象的属性名相同时,可以使用简写。
// Before
const firstName = "John";
const lastName = "Doe";
const user = {
firstName: firstName,
lastName: lastName,
age: 40
};
console.log(user); // Output: { firstName: 'John', lastName: 'Doe', age: 40 }
// After
const firstName = "John";
const lastName = "Doe";
const age = 40; // 'age' variable also used directly
const user = {
firstName,
lastName,
age
};
console.log(user); // Output: { firstName: 'John', lastName: 'Doe', age: 40 }
23. 使用 for...of 循环
直接迭代可迭代对象(数组、字符串、Map、Set、NodeList),无需处理索引。
// Before (for iterating values)
const fruits = ["apple", "banana", "orange"];
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
// After
const fruits = ["apple", "banana", "orange"];
for (const fruit of fruits) {
console.log(fruit);
}
/*
Output:
apple
banana
orange
*/
// Iterating over a string
for (const char of "hello") {
console.log(char);
}
/*
Output:
h
e
l
l
o
*/
24. 无需临时变量即可交换变量
使用数组解构在一行代码中交换两个变量的值。
// Before
let a = 1;
let b = 2;
let temp = a;
a = b;
b = temp;
console.log(a, b); // Output: 2 1
// After
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b); // Output: 2 1
25. console.table():以表格格式显示数据
一个非常棒的调试工具,用于在浏览器控制台中以可读的表格形式显示对象数组或对象。
const users = [
{ id: 1, name: "Alice", age: 28 },1, name: "Alice", age: 28 },
{ id: 2, name: "Bob", age: 35 },
{ id: 3, name: "Charlie", age: 22 }
];
console.table(users);
/*
Output in browser console (table format):
(index) | id | name | age
--------|----|---------|----
0 | 1 | "Alice" | 28
1 | 2 | "Bob" | 35
2 | 3 | "Charlie"| 22
*/
const person = {
firstName: "Jane",
lastName: "Doe",
occupation: "Developer"
};
console.table(person);
/*
Output in browser console (table format):
(index) | Value
----------|----------
firstName | "Jane"
lastName | "Doe"
occupation| "Developer"
*/
写在最后
掌握这 25 个 JavaScript 快捷键无疑会让你的代码更简洁、更易写,也更有趣。它们是现代 JavaScript 的关键特性,掌握它们将显著提升你的工作效率和应用程序的质量。
开始将它们融入你的日常开发项目中来,你很快就会像真正的 JavaScript 大师一样写出精彩的代码!