普通视图

发现新文章,点击刷新页面。
今天 — 2025年12月4日首页

JavaScript 一些小特性:让你的代码更优雅高效

2025年12月4日 16:26

作为前端开发者,掌握这些 JavaScript 高级特性能大幅提升你的开发效率和代码质量。本文整理了日常开发中最实用的技巧,每个都配有实战代码示例。


1. 解构赋值 (Destructuring)

解构赋值让你从数组或对象中快速提取值,告别繁琐的逐个赋值。

对象解构

// 基础用法
const user = { name: '张三', age: 25, city: '北京' };
const { name, age } = user;
console.log(name, age); // 张三 25

// 重命名 + 默认值
const { name: userName, gender = '未知' } = user;
console.log(userName, gender); // 张三 未知

// 嵌套解构
const response = {
  data: {
    user: { id: 1, name: 'John' },
    token: 'abc123'
  }
};
const { data: { user: { id }, token } } = response;
console.log(id, token); // 1 abc123

数组解构

// 交换变量(不需要临时变量)
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2 1

// 跳过某些元素
const [first, , third] = [1, 2, 3];
console.log(first, third); // 1 3

// 剩余元素
const [head, ...tail] = [1, 2, 3, 4];
console.log(head, tail); // 1 [2, 3, 4]

2. 展开运算符与剩余参数 (Spread & Rest)

展开运算符

// 合并数组
const arr1 = [1, 2];
const arr2 = [3, 4];
const merged = [...arr1, ...arr2]; // [1, 2, 3, 4]

// 浅拷贝对象(常用于 React/Vue 状态更新)
const original = { a: 1, b: 2 };
const copied = { ...original, c: 3 }; // { a: 1, b: 2, c: 3 }

// 合并对象(后面的属性覆盖前面的)
const defaults = { theme: 'light', lang: 'zh' };
const userConfig = { theme: 'dark' };
const config = { ...defaults, ...userConfig }; // { theme: 'dark', lang: 'zh' }

剩余参数

// 函数接收不定数量参数
function sum(...numbers) {
  return numbers.reduce((acc, num) => acc + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10

// 解构时收集剩余属性
const { id, ...rest } = { id: 1, name: 'test', value: 100 };
console.log(rest); // { name: 'test', value: 100 }

3. 可选链与空值合并 (?. 和 ??)

这两个操作符是处理 null/undefined 的神器,能大幅减少代码中的条件判断。

可选链操作符 (?.)

const user = {
  profile: {
    address: {
      city: '上海'
    }
  }
};

// 传统写法(繁琐且易出错)
const city = user && user.profile && user.profile.address && user.profile.address.city;

// 可选链写法(简洁优雅)
const city = user?.profile?.address?.city; // '上海'
const country = user?.profile?.address?.country; // undefined(不会报错)

// 用于方法调用
const result = user?.getName?.(); // 如果 getName 不存在,返回 undefined

// 用于数组索引
const firstItem = arr?.[0];

空值合并操作符 (??)

// ?? 只在值为 null 或 undefined 时使用默认值
const value1 = null ?? '默认值'; // '默认值'
const value2 = undefined ?? '默认值'; // '默认值'
const value3 = 0 ?? '默认值'; // 0(0 是有效值)
const value4 = '' ?? '默认值'; // ''(空字符串是有效值)

// 对比 || 运算符(会把 0、''、false 也当作假值)
const value5 = 0 || '默认值'; // '默认值'(可能不是你想要的)

// 实际应用:配置项处理
function createConfig(options) {
  return {
    timeout: options?.timeout ?? 3000,
    retries: options?.retries ?? 3,
    debug: options?.debug ?? false
  };
}

4. 数组高阶方法

这些方法让你告别 for 循环,写出更声明式、更易读的代码。

map - 数据转换

const users = [
  { id: 1, name: 'Alice', age: 25 },
  { id: 2, name: 'Bob', age: 30 }
];

// 提取所有用户名
const names = users.map(user => user.name); // ['Alice', 'Bob']

// 数据格式转换
const options = users.map(({ id, name }) => ({
  value: id,
  label: name
}));
// [{ value: 1, label: 'Alice' }, { value: 2, label: 'Bob' }]

filter - 数据过滤

const numbers = [1, 2, 3, 4, 5, 6];

// 过滤偶数
const evens = numbers.filter(n => n % 2 === 0); // [2, 4, 6]

// 过滤空值
const items = ['a', '', null, 'b', undefined, 'c'];
const validItems = items.filter(Boolean); // ['a', 'b', 'c']

reduce - 数据聚合

// 求和
const sum = [1, 2, 3, 4].reduce((acc, num) => acc + num, 0); // 10

// 数组转对象(非常实用!)
const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' }
];
const userMap = users.reduce((acc, user) => {
  acc[user.id] = user;
  return acc;
}, {});
// { 1: { id: 1, name: 'Alice' }, 2: { id: 2, name: 'Bob' } }

// 数组分组
const items = [
  { type: 'fruit', name: '苹果' },
  { type: 'vegetable', name: '白菜' },
  { type: 'fruit', name: '香蕉' }
];
const grouped = items.reduce((acc, item) => {
  const key = item.type;
  acc[key] = acc[key] || [];
  acc[key].push(item);
  return acc;
}, {});
// { fruit: [...], vegetable: [...] }

find & findIndex - 查找元素

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' }
];

const user = users.find(u => u.id === 2); // { id: 2, name: 'Bob' }
const index = users.findIndex(u => u.id === 2); // 1

some & every - 条件判断

const numbers = [1, 2, 3, 4, 5];

numbers.some(n => n > 4); // true(至少有一个大于4)
numbers.every(n => n > 0); // true(所有都大于0)

flatMap - 扁平化映射

const sentences = ['Hello World', 'Good Morning'];
const words = sentences.flatMap(s => s.split(' '));
// ['Hello', 'World', 'Good', 'Morning']

5. Promise 与 async/await

Promise 基础

// 创建 Promise
const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ data: 'success' });
    }, 1000);
  });
};

// Promise 链式调用
fetchData()
  .then(result => console.log(result))
  .catch(error => console.error(error))
  .finally(() => console.log('完成'));

async/await - 同步风格写异步

// 基础用法
async function getData() {
  try {
    const response = await fetch('/api/users');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('请求失败:', error);
    throw error;
  }
}

// 并行请求(重要!避免串行等待)
async function fetchAll() {
  // ❌ 串行执行,慢
  const user = await fetchUser();
  const posts = await fetchPosts();
  
  // ✅ 并行执行,快
  const [user, posts] = await Promise.all([
    fetchUser(),
    fetchPosts()
  ]);
}

// Promise.allSettled - 等待所有完成(不管成功失败)
const results = await Promise.allSettled([
  fetch('/api/a'),
  fetch('/api/b'),
  fetch('/api/c')
]);
// 每个结果包含 status: 'fulfilled' | 'rejected'

6. 模板字符串高级用法

多行字符串与表达式

const name = '张三';
const score = 95;

// 多行 + 表达式
const message = `
  学生: ${name}
  成绩: ${score}
  等级: ${score >= 90 ? '优秀' : '良好'}
`;

// 嵌套模板字符串
const items = ['苹果', '香蕉', '橙子'];
const html = `
  <ul>
    ${items.map(item => `<li>${item}</li>`).join('')}
  </ul>
`;

标签模板(Tagged Templates)

// 自定义模板处理函数
function highlight(strings, ...values) {
  return strings.reduce((result, str, i) => {
    const value = values[i] ? `<mark>${values[i]}</mark>` : '';
    return result + str + value;
  }, '');
}

const name = '张三';
const city = '北京';
const result = highlight`${name} 来自 ${city}`;
// '<mark>张三</mark> 来自 <mark>北京</mark>'

7. 对象属性简写与计算属性名

// 属性简写
const name = '张三';
const age = 25;
const user = { name, age }; // 等同于 { name: name, age: age }

// 方法简写
const obj = {
  sayHello() {
    console.log('Hello');
  }
};

// 计算属性名(动态 key)
const key = 'dynamicKey';
const obj = {
  [key]: 'value',
  [`prefix_${key}`]: 'prefixed value',
  [`method_${key}`]() {
    return 'dynamic method';
  }
};
console.log(obj.dynamicKey); // 'value'

// 实际应用:动态设置状态
function updateState(key, value) {
  setState(prev => ({
    ...prev,
    [key]: value
  }));
}

8. 短路求值与逻辑赋值

短路求值

// && 短路:第一个为真才执行第二个
const result = condition && doSomething();
isLoggedIn && showDashboard();

// || 短路:第一个为假才执行第二个
const name = userName || '匿名用户';

// 条件渲染(React 常用)
{isLoading && <Spinner />}
{error || <SuccessMessage />}

逻辑赋值运算符(ES2021)

// ||= 空值时赋值
let name = '';
name ||= '默认名称'; // name = '默认名称'

// &&= 有值时赋值
let user = { name: '张三' };
user &&= { ...user, updated: true };

// ??= null/undefined 时赋值
let config = null;
config ??= { theme: 'dark' };

// 实际应用:懒初始化
class Cache {
  data = null;
  
  getData() {
    return this.data ??= this.loadData();
  }
}

9. 对象与数组新方法

Object 方法

// Object.entries - 对象转键值对数组
const obj = { a: 1, b: 2, c: 3 };
Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key}: ${value}`);
});

// Object.fromEntries - 键值对数组转对象
const entries = [['a', 1], ['b', 2]];
const obj = Object.fromEntries(entries); // { a: 1, b: 2 }

// 实用技巧:过滤对象属性
const original = { a: 1, b: 2, c: 3, d: 4 };
const filtered = Object.fromEntries(
  Object.entries(original).filter(([key, value]) => value > 2)
);
// { c: 3, d: 4 }

// Object.keys / Object.values
const keys = Object.keys(obj); // ['a', 'b', 'c']
const values = Object.values(obj); // [1, 2, 3]

Array 新方法

// Array.from - 类数组转真数组
const nodeList = document.querySelectorAll('div');
const divArray = Array.from(nodeList);

// 带映射函数
const numbers = Array.from({ length: 5 }, (_, i) => i + 1);
// [1, 2, 3, 4, 5]

// Array.isArray - 判断是否为数组
Array.isArray([1, 2, 3]); // true
Array.isArray('hello'); // false

// at() - 支持负索引
const arr = [1, 2, 3, 4, 5];
arr.at(-1); // 5(最后一个元素)
arr.at(-2); // 4

10. Map 与 Set

Map - 键值对集合

const map = new Map();

// 任意类型作为 key(比普通对象强大)
const objKey = { id: 1 };
map.set(objKey, 'object value');
map.set('string', 'string value');
map.set(123, 'number value');

// 常用操作
map.get(objKey); // 'object value'
map.has('string'); // true
map.delete('string');
map.size; // 2

// 遍历
map.forEach((value, key) => {
  console.log(key, value);
});

// 实际应用:缓存函数结果
const cache = new Map();
function memoizedFetch(url) {
  if (cache.has(url)) {
    return cache.get(url);
  }
  const result = fetch(url).then(r => r.json());
  cache.set(url, result);
  return result;
}

Set - 唯一值集合

const set = new Set([1, 2, 3, 3, 4, 4]);
console.log([...set]); // [1, 2, 3, 4](自动去重)

// 数组去重(最简洁的方式)
const unique = [...new Set(array)];

// 交集、并集、差集
const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);

const union = new Set([...a, ...b]); // 并集 {1, 2, 3, 4}
const intersection = new Set([...a].filter(x => b.has(x))); // 交集 {2, 3}
const difference = new Set([...a].filter(x => !b.has(x))); // 差集 {1}

11. Proxy 与 Reflect

Proxy 可以拦截对象的操作,是 Vue 3 响应式系统的核心。

const target = { name: '张三', age: 25 };

const handler = {
  get(obj, prop) {
    console.log(`读取属性: ${prop}`);
    return Reflect.get(obj, prop);
  },
  set(obj, prop, value) {
    console.log(`设置属性: ${prop} = ${value}`);
    return Reflect.set(obj, prop, value);
  }
};

const proxy = new Proxy(target, handler);
proxy.name; // 控制台: 读取属性: name
proxy.age = 26; // 控制台: 设置属性: age = 26

// 实际应用:数据验证
const validator = {
  set(obj, prop, value) {
    if (prop === 'age' && typeof value !== 'number') {
      throw new TypeError('Age must be a number');
    }
    return Reflect.set(obj, prop, value);
  }
};

12. Class 语法与私有属性

class User {
  // 私有属性(ES2022)
  #password;
  
  // 静态属性
  static count = 0;
  
  constructor(name, password) {
    this.name = name;
    this.#password = password;
    User.count++;
  }
  
  // 私有方法
  #hashPassword(pwd) {
    return `hashed_${pwd}`;
  }
  
  // getter/setter
  get password() {
    return '******';
  }
  
  set password(value) {
    this.#password = this.#hashPassword(value);
  }
  
  // 静态方法
  static getCount() {
    return User.count;
  }
}

const user = new User('张三', '123456');
console.log(user.#password); // SyntaxError: 私有属性不可访问
console.log(User.getCount()); // 1

13. 模块化 (ES Modules)

// utils.js - 命名导出
export const formatDate = (date) => { /* ... */ };
export const formatNumber = (num) => { /* ... */ };

// user.js - 默认导出
export default class User { /* ... */ }

// main.js - 导入
import User from './user.js'; // 默认导入
import { formatDate, formatNumber } from './utils.js'; // 命名导入
import { formatDate as fd } from './utils.js'; // 重命名导入
import * as utils from './utils.js'; // 全部导入

// 动态导入(代码分割、按需加载)
const module = await import('./heavy-module.js');

// 条件导入
if (needFeature) {
  const { feature } = await import('./feature.js');
  feature();
}

14. 实用技巧汇总

数字分隔符

const billion = 1_000_000_000; // 更易读
const bytes = 0xFF_FF_FF_FF;

对象属性存在性检查

// 使用 in 操作符
if ('name' in user) { /* ... */ }

// 使用 hasOwnProperty
if (Object.hasOwn(user, 'name')) { /* ... */ } // ES2022

快速数组操作

// 快速创建数组
const arr = Array(5).fill(0); // [0, 0, 0, 0, 0]
const range = [...Array(5).keys()]; // [0, 1, 2, 3, 4]

// 数组最后一项
const last = arr.at(-1); // ES2022
const last = arr[arr.length - 1]; // 传统方式

对象冻结

const config = Object.freeze({
  API_URL: 'https://api.example.com',
  TIMEOUT: 5000
});
config.API_URL = 'new url'; // 静默失败(严格模式下报错)

总结

掌握这些 JavaScript 高级特性,能让你:

  1. 📝 代码更简洁 - 解构、展开运算符、箭头函数
  2. 🛡️ 代码更安全 - 可选链、空值合并避免空指针
  3. 🚀 开发更高效 - 数组高阶方法、async/await
  4. 🏗️ 架构更清晰 - Class、模块化、Proxy

这些特性都是现代 JavaScript 开发的标配,建议在日常开发中多加练习!


📌 文章持续更新中,欢迎评论区交流更多实用技巧!

如果觉得有帮助,请点赞👍收藏⭐关注➕,你的支持是我更新的动力!

❌
❌