下面列出了 12 个 JavaScript 小技巧,这些技巧可以帮助你编写更简洁、高效的代码。
如果你已经在使用其中的一些技巧,那就巩固一下吧!需要注意的是为了兼容旧版浏览器,记得按需注入垫片(polyfill)。
1. 空值合并运算符(??)
使用 ?? 来赋默认值,当 ?? 的左侧值为 null 或者 undefined 时,?? 就会使用右侧的默认值。
const placeholder = props.placeholder ?? '请输入'
console.log(placeholder) // props.placeholder 为 null 或 undefined 时,输出“请输入”
?? 对比函数或解构默认值,唯一的区别在于对 null 的处理,?? 如上在面对 null 时也会使用默认值,而函数或解构默认值则会使用 null。
function foo(text = 'default') {
return text
}
let input1
console.log(input1 ?? 'default', foo(input1))
// 输出 default default
const input2 = null
console.log(input2 ?? 'default', foo(input2))
// 输出 default null
const input3 = 'value'
console.log(input3 ?? 'default', foo(input3))
// 输出 value value
在项目代码中,也会看到使用逻辑或运算符 || 来赋默认值,|| 运算符在左侧值为 0、空字符串('')、NaN、false、null、undefined 等 falsy 值时,都会使用默认值。
let input1
console.log(input1 ?? 'default', input1 || 'default')
// 输出 default default
const input2 = false
console.log(input2 ?? 'default', input2 || 'default')
// 输出 false default
const input3 = 'value'
console.log(input3 ?? 'default', input3 || 'default')
// 输出 value value
故推荐使用 ?? 来赋默认值,也可以使用函数或解构默认值,不过要注意 null 值,而 || 更适用于 if 等逻辑判断。
2. 可选链操作符(?.)
可选链运算符(?.)用于访问对象的属性或方法,当访问的对象或方法是 undefined 或 null,表达式会短路并计算为 undefined,而不是抛出错误。
const obj = {
foo: { bar: { a: 3 } }
}
const obj2 = {}
function getA(o) {
return o && o.foo && o.foo.bar && o.foo.bar.a
}
function getA2(o) {
return o?.foo?.bar?.a
}
// 用 && 来获取深层对象
console.log(getA(obj)) // 输出3
console.log(getA(obj2)) // 输出 undefined
console.log(getA2(obj)) // 输出3
console.log(getA2(obj2)) // 输出 undefined
可以看到使用可选链运算符(?.)在获取对象属性上使用会更方便。
3. 使用解构赋值
解构赋值可以快速提取对象或数组中的值,减少冗余代码。
// 对象解构
const user = { name: 'John', age: 30 };
const { name, age } = user;
console.log(name, age); // John 30
// 数组解构
const numbers = [1, 2, 3];
const [first, second] = numbers;
console.log(first, second); // 1 2
4. 字符串方法
使用 startsWith、endsWith、includes 方法来判断字符串是否包含某个子串。
'Hello World'.startsWith('Hello') // true
'Hello World'.endsWith('World') // true
'Hello World'.includes('World') // true
相比与 indexOf 方法,startsWith、endsWith、includes 代码可读性更高。
const isPython = 'Hello Python'.indexOf('Python') !== -1 // true
const isJS = 'Hello JavaScript'.includes('JavaScript') // true
5. 数组方法
使用 map、filter、some、every 等方法来操作数组。
const arr = [
{ name: '小明', age: 16 },
{ name: '张三', age: 18 },
{ name: '李四', age: 20 }
]
const ageArr = arr.map(item => item.age) // [16, 18, 20]
const adults = arr.filter(item => item.age >= 18) // [{ name: '张三', age: 18 }, { name: '李四', age: 20 }]
const hasChild = arr.some(item => item.age < 18) // true
const isAllAdults = arr.every(item => item.age >= 18) // false
相比于使用 for 循环遍历数组来写业务逻辑,map、filter、some、every 等方法让你编码更高效,同时可读性更高。
6. 使用 Set 去重
Set 可以快速去除数组中的重复项。
const numbers = [1, 2, 2, 3, 4, 4];
const uniqueNumbers = [...new Set(numbers)];
console.log(uniqueNumbers); // [1, 2, 3, 4]
7. 使用 Array.from 将类数组转换为数组
将 NodeList、arguments 等类数组对象转换为真正的数组。
const nodeList = document.querySelectorAll('div');
const divArray = Array.from(nodeList);
8. 使用策略模式优化 if
在一些场景中,if 分支会比较多,可以使用策略模式优化。
// if 判断
function renderSports = (sports) => {
if (sports === 'basketball') {
return'篮球'
} elseif (sports === 'football') {
return'足球'
} elseif (sports === 'tennis') {
return'网球'
} else {
return'--'
}
}
// 策略模式优化
function renderSports2 = (sports) => {
const sportsMap = {
basketball: '篮球',
football: '足球',
tennis: '网球',
}
return sportsMap[sports] || '--'
}
使用策略模式优化后,可以少写一些 if 语句,代码也更符合设计模式。
9. 使用快速生成代码片段
VSCode 中有提供代码片段插件,这些插件能帮助你高效的写代码,当然你也可以自己编写代码片段。
10. Chrome DevTools 替换接口内容
当接口返回的内容无法覆盖页面所有展示情况时,我们可以使用 Chrome DevTools 的替换内容功能来修改接口响应,从而在不用本地模拟数据的情况下完成功能验证。
11. 从控制台复制长变量
Chrome 控制台遇到内容比较长的变量时,不会直接平铺展示全部内容,比如字符串较长时中间会显示省略号、数组较长时会分块展示等。如果你想复制这个内容,就会比较困难,这时可以使用 Chrome Devtools 的复制变量功能。
12. 使用 classnames 处理类名
使用 classnames 能更高效的处理类名,同时还能使类名逻辑更清晰,便于理解和维护。
// 直接处理类名
let buttonClass = 'btn';
if (isPrimary) {
buttonClass += ' btn-primary';
}
if (isDisabled) {
buttonClass += ' btn-disabled';
}
// 使用 classNames 处理类名
const buttonClass = classNames('btn', {
'btn-primary': isPrimary,
'btn-disabled': isDisabled,
})