2024年17个必知必会的 ES6+ 特性总结【场景实战版】

 作为一名前端开发者,熟练运用 ES6+ 特性是基本功。本文精选最常用、最实用的JavaScript 新特性,结合实际开发场景,帮你攻克开发难点,提升代码质量。告别繁琐的老式写法,拥抱现代JavaScript。

1. 解构赋值:优雅地获取数据

// 对象解构
const user = {
    name: 'Tom',
    age: 25,
    address: {
        city: 'Shanghai',
        street: 'Nanjing Road'
    }
};

// 基础解构
const { name, age } = user;

// 深层解构
const { address: { city } } = user;

// 设置默认值
const { country = 'China' } = user;

// 数组解构
const [first, second, ...rest] = [1, 2, 3, 4, 5];

/* 1. 解构赋值:实战应用 */

// 场景1: 接口数据处理
const handleResponse = (response) => {
  const { code, data: { userInfo, permissions } } = response;
  return code === 200 ? userInfo : null;
};

// 场景2: React组件属性处理
function UserCard({ name, avatar, role = 'user', ...props }) {
  return (/* 组件内容 */);
}

 接口处理:后端返回数据结构发生异常时(如从数组变为null),解构赋值会抛出错误。这是因为解构要求目标具有特定的数据结构,即使在错误状态下,数据类型也应保持一致。比如API正常返回数组时使用了解构,那么在异常情况下也应返回空数组[],而不是null或其他类型。这样可以确保解构操作的安全性,并保持类型的一致性。

2. 展开运算符:代码更简洁

// 对象合并
const defaultConfig = { theme: 'dark', lang: 'en' };
const userConfig = { theme: 'light' };
const config = { ...defaultConfig, ...userConfig };

// 数组操作
const nums = [1, 2, 3];
const moreNums = [...nums, 4, 5];  // [1, 2, 3, 4, 5]

// 函数参数
function sum(...numbers) {
    return numbers.reduce((a, b) => a + b, 0);
}

/* 展开运算符:实战应用 */

// 场景1: 配置合并
const mergeConfig = (defaultConfig, userConfig) => {
  return {
    ...defaultConfig,
    ...userConfig,
    timestamp: Date.now()
  };
};

// 场景2: 不可变数据处理
const addTodo = (todos, newTodo) => {
  return [...todos, newTodo];
};

3. 可选链操作符:告别层层判断

// 之前的写法
const street = user && user.address && user.address.street;

// 现代写法
const street = user?.address?.street;

// 数组使用
const first = arr?.[0];

// 函数调用
const result = func?.();

/* 可选链:实战应用 */

// 场景1: 嵌套数据访问
const getUserCity = (user) => {
  return user?.address?.city ?? '未知城市';
};

// 场景2: 函数安全调用
const logEvent = (analytics) => {
  analytics?.logEvent?.('page_view');
};

4. 空值合并:更智能的默认值

// 之前的写法
const value = data || 'default';  // 0, '', false 都会被替换

// 现代写法
const value = data ?? 'default';  // 只有 null 和 undefined 会被替换


/* 空值合并:实战应用 */

// 场景1: 表单默认值
const getFormValue = (form) => {
  return {
    name: form.name ?? '匿名用户',
    age: form.age ?? 18,
    city: form.city ?? '未知'
  };
};

// 场景2: 配置参数
const initConfig = (config) => {
  return {
    theme: config.theme ?? 'light',
    lang: config.lang ?? 'zh-CN',
    timeout: config.timeout ?? 3000
  };
};

5. 模板字符串:更强大的字符串处理

const name = 'Tom';
const age = 25;

// 基础用法
const greeting = `Hello ${name}, you are ${age} years old!`;

// 多行文本
const html = `
    <div>
        <h1>${name}</h1>
        <p>Age: ${age}</p>
    </div>
`;

// 标签模板
function highlight(strings, ...values) {
    return strings.reduce((result, str, i) => 
        `${result}${str}${values[i] ? `<span class="highlight">${values[i]}</span>` : ''}`
    , '');
}

const highlighted = highlight`The name is ${name}!`;

/* 模板字符串:实战应用 */

// 场景1: 动态消息生成
const createMessage = (user, action) => {
  return `用户 ${user.name} 在 ${new Date().toLocaleString()} ${action}`;
};

// 场景2: URL构建
const buildApiUrl = (endpoint, params) => {
  return `${API_BASE}/${endpoint}?token=${params.token}`;
};

6. Promise 和 async/await:优雅的异步处理

// Promise 链式调用
fetch('/api/user')
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error(error));

// async/await 写法
async function getUser() {
    try {
        const response = await fetch('/api/user');
        const data = await response.json();
        console.log(data);
    } catch (error) {
        console.error(error);
    }
}

// Promise 并行
const [users, posts] = await Promise.all([
    fetch('/api/users').then(r => r.json()),
    fetch('/api/posts').then(r => r.json())
]);

/*  Promise和async/await:实战应用 */

// 场景1: 并发请求
const loadDashboard = async () => {
  const [users, orders, stats] = await Promise.all([
    fetchUsers(),
    fetchOrders(),
    fetchStats()
  ]);
  return { users, orders, stats };
};

// 场景2: 错误重试
const fetchWithRetry = async (url, retries = 3) => {
  for(let i = 0; i < retries; i++) {
    try {
      return await fetch(url);
    } catch(err) {
      if (i === retries - 1) throw err;
      await new Promise(r => setTimeout(r, 1000 * i));
    }
  }
};

7. 对象和数组的新方法

// Object 新方法
const obj = { name: 'Tom', age: 25 };
Object.entries(obj);  // [['name', 'Tom'], ['age', 25]]
Object.fromEntries([['name', 'Tom'], ['age', 25]]);  // { name: 'Tom', age: 25 }

// Array 新方法
const arr = [1, 2, 3, 4, 5];

// find 和 findLast
const found = arr.find(x => x > 3);  // 4
const foundLast = arr.findLast(x => x > 3);  // 5

// flat 和 flatMap
const nested = [1, [2, 3], [4, [5]]];
nested.flat(2);  // [1, 2, 3, 4, 5]

// at - 支持负数索引
arr.at(-1);  // 5

/* 对象和数组新方法:实战应用 */

// 场景1: 数据转换
const arrayToObject = (array) => {
  return Object.fromEntries(
    array.map(item => [item.id, item])
  );
};

// 场景2: 分页数据处理
const getPageItems = (items, page, pageSize) => {
  return items.slice((page - 1) * pageSize).slice(0, pageSize);
};

8. 类的私有字段和私有方法

class User {
    #privateField = 'private';
    
    #privateMethod() {
        return 'private method';
    }
    
    publicMethod() {
        console.log(this.#privateField);
        console.log(this.#privateMethod());
    }
}

/* 8. 类的私有字段:实战应用 */

// 场景1: 缓存管理器
class CacheManager {
  #cache = new Map();
  #maxAge;

  constructor(maxAge = 3600000) {
    this.#maxAge = maxAge;
  }

  set(key, value) {
    this.#cache.set(key, {
      value,
      timestamp: Date.now()
    });
  }
}

// 场景2: 状态管理
class Store {
  #state = {};
  #listeners = new Set();

  subscribe(listener) {
    this.#listeners.add(listener);
    return () => this.#listeners.delete(listener);
  }
}

9. Map 和 Set 数据结构

// Map - 键值对集合,任何类型都可以作为键
const map = new Map();
map.set('key', 'value');
map.set(objKey, 'value');  // 对象也可以作为键

// Map 的常用操作
for (let [key, value] of map) {
    console.log(`${key} = ${value}`);
}

// WeakMap - 弱引用版本的Map
const weakMap = new WeakMap();  // 用于防止内存泄漏

// Set - 值的集合,自动去重
const set = new Set([1, 2, 2, 3, 3]);  // {1, 2, 3}

// Set 的实用操作
const intersection = new Set([...set1].filter(x => set2.has(x)));
const difference = new Set([...set1].filter(x => !set2.has(x)));

/* Map和Set:实战应用 */

// 场景1: 用户会话管理
class SessionManager {
  #sessions = new Map();

  addSession(userId, token) {
    this.#sessions.set(userId, {
      token,
      lastActive: Date.now()
    });
  }
}

// 场景2: unique标签系统
class TagManager {
  #tags = new Set();

  addTags(tags) {
    tags.forEach(tag => this.#tags.add(tag));
    return Array.from(this.#tags);
  }
}

10. 数组高级操作

// 数组分组(ES2023)
const items = [
    {type: 'fruit', name: 'apple'},
    {type: 'vegetable', name: 'carrot'},
    {type: 'fruit', name: 'banana'},
];

const grouped = Object.groupBy(items, item => item.type);
/*
{
    fruit: [{type: 'fruit', name: 'apple'}, {type: 'fruit', name: 'banana'}],
    vegetable: [{type: 'vegetable', name: 'carrot'}]
}
*/

// 数组操作新方法
const arr = [1, 2, 3, 4, 5];

// toSorted, toReversed - 不修改原数组的版本
const sorted = arr.toSorted((a, b) => b - a);
const reversed = arr.toReversed();

// with - 不修改原数组的替换
const newArr = arr.with(2, 10);  // [1, 2, 10, 4, 5]


/* 数组高级操作:实战应用 */

// 场景1: 分页列表排序(不改变原数组)
const sortPageItems = (items, sortKey, sortOrder = 'asc') => {
  return items.toSorted((a, b) => {
    return sortOrder === 'asc' 
      ? a[sortKey] - b[sortKey]
      : b[sortKey] - a[sortKey];
  });
};

// 场景2: 轮播图片索引
class Carousel {
  #images = ['1.jpg', '2.jpg', '3.jpg', '4.jpg'];
  #currentIndex = 0;

  prev() {
    // 使用at处理负数索引,轻松获取末尾元素
    return this.#images.at(--this.#currentIndex);
  }

  next() {
    return this.#images.at(++this.#currentIndex % this.#images.length);
  }
}

// 场景3: 列表更新(不修改原数组)
const updateListItem = (list, index, newValue) => {
  return list.with(index, newValue);
};

// 场景4: 反转展示历史记录
class History {
  #records = [];

  add(record) {
    this.#records.push(record);
  }

  // 最新的记录先显示
  getRecentRecords(limit = 10) {
    return this.#records.toReversed().slice(0, limit);
  }
}

// 场景5: 数据导出排序
const exportSortedData = (data) => {
  // 不影响原始数据的排序
  const sortedData = data.toSorted((a, b) => a.name.localeCompare(b.name));
  return sortedData;
};

11. 字符串新特性

// replaceAll
const str = 'hello hello';
str.replaceAll('hello', 'hi');  // 'hi hi'

// matchAll
const regex = /t(e)(st(\d?))/g;
const text = 'test1 test2 test3';
const matches = [...text.matchAll(regex)];

// padStart/padEnd
'5'.padStart(2, '0');  // '05'
'hello'.padEnd(10, '*');  // 'hello*****'

/* 字符串新特性:实战应用 */

// 场景1: 格式化处理
const formatAmount = (amount) => {
  return amount.toString().padStart(3, '0');
};

// 场景2: 模板替换
const replaceTemplate = (template, data) => {
  return template.replaceAll(
    /\{\{(\w+)\}\}/g,
    (_, key) => data[key] ?? ''
  );
};

12. 类的新特性

class Product {
    // 公共字段声明
    name;
    price;
    
    // 私有字段
    #stock;
    
    // 静态私有字段
    static #count = 0;
    
    // 静态公共方法
    static createProduct(name, price) {
        return new Product(name, price);
    }
    
    // 类字段初始化器
    tax = 0.1;
    
    // getter/setter
    get inStock() {
        return this.#stock > 0;
    }
    
    // 私有方法
    #calculateDiscount() {
        return this.price * 0.1;
    }
}

/* 类的新特性:实战应用 */

// 场景1: 表单验证器
class FormValidator {
  static #rules = new Map();

  static addRule(name, validator) {
    this.#rules.set(name, validator);
  }

  validate(data) {
    // 验证逻辑
  }
}

13. 高级函数特性

// 函数参数默认值
function greet(name = 'Guest', greeting = `Hello`) {
    return `${greeting}, ${name}!`;
}

// 箭头函数和this
class Handler {
    constructor() {
        this.value = 42;
    }
    
    normal() {
        setTimeout(function() {
            console.log(this.value); // undefined
        });
    }
    
    arrow() {
        setTimeout(() => {
            console.log(this.value); // 42
        });
    }
}

// 函数组合
const pipe = (...fns) => x => fns.reduce((y, f) => f(y), x);
const add10 = x => x + 10;
const multiply2 = x => x * 2;
const combined = pipe(add10, multiply2);


/* 13. 高级函数特性:实战应用 */

// 场景1: API请求装饰器
const withLoading = (fn) => async (...args) => {
  try {
    showLoading();
    return await fn(...args);
  } finally {
    hideLoading();
  }
};

// 场景2: 函数管道
const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x);

14. 正则表达式增强

// 命名捕获组
const regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2024-02-07'.match(regex);
console.log(match.groups.year);  // 2024

// 后行断言
const price = '$123.45'.match(/(?<=\$)\d+\.\d+/)[0];

// Unicode 属性转义
const regex = /\p{Emoji}/u;
console.log(regex.test('🎉'));  // true


/* 正则表达式增强:实战应用 */

// 场景1: 日期解析
const parseDate = (dateStr) => {
  const regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
  const { groups } = dateStr.match(regex);
  return new Date(groups.year, groups.month - 1, groups.day);
};

// 场景2: 金额提取
const extractAmount = (text) => {
  return text.match(/(?<=\$)\d+(\.\d{2})?/)[0];
};

15. 模块化高级特性

// 动态导入
const loadModule = async () => {
    const module = await import('./module.js');
    module.doSomething();
};

// 模块命名空间导出
export * as utils from './utils.js';

// 导出默认值和具名导出组合
export { default as Main, utilities } from './module.js';

/* 模块化高级特性:实战应用 */

// 场景1: 动态加载
const loadModule = async (moduleName) => {
  const module = await import(`./modules/${moduleName}.js`);
  return module.default;
};

// 场景2: 统一导出
export * as validators from './validators.js';

16. 实用的编程模式

// 管道操作
const double = n => n * 2;
const increment = n => n + 1;
const square = n => n * n;

// 函数式编程管道
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);
const compute = pipe(double, increment, square);
console.log(compute(3));  // ((3 * 2 + 1) ^ 2) = 49

// 装饰器模式(Stage 3提案)
function log(target, name, descriptor) {
    // 方法装饰器
}

// 对象属性监听
const handler = {
    get: function(target, prop) {
        console.log(`Accessing ${prop}`);
        return target[prop];
    }
};
const proxy = new Proxy({}, handler);

/* 实用编程模式:实战应用 */

// 场景1: 状态管理
const createStore = (reducer) => {
  let state = reducer(undefined, {});
  const listeners = new Set();

  return {
    getState: () => state,
    dispatch: (action) => {
      state = reducer(state, action);
      listeners.forEach(listener => listener());
    },
    subscribe: (listener) => {
      listeners.add(listener);
      return () => listeners.delete(listener);
    }
  };
};

17. 错误处理最佳实践

// 自定义错误类
class ValidationError extends Error {
    constructor(message) {
        super(message);
        this.name = 'ValidationError';
    }
}

// 异步错误处理
async function fetchData() {
    try {
        const response = await fetch('/api/data');
        if (!response.ok) {
            throw new ValidationError('API请求失败');
        }
        return await response.json();
    } catch (error) {
        if (error instanceof ValidationError) {
            // 处理验证错误
        } else {
            // 处理其他错误
        }
    } finally {
        // 清理工作
    }
}

/* 错误处理最佳实践:实战应用 */


// 场景1: 异步错误边界
const withErrorBoundary = async (fn) => {
  try {
    return await fn();
  } catch (error) {
    if (error instanceof ApiError) {
      handleApiError(error);
    } else {
      reportError(error);
    }
    throw error;
  }
};

实用技巧

 1. 链式可选操作

// 组合使用可选链和空值合并
const username = data?.user?.profile?.name ?? 'Anonymous';

2. 动态对象属性

const field = 'name';
const value = 'Tom';
const user = {
    [field]: value
};

3. 数组去重

const unique = [...new Set([1, 1, 2, 3, 3])];  // [1, 2, 3]

注意事项

  • 解构赋值和展开运算符可能影响性能,处理大数据时需谨慎
  • 可选链在频繁调用时可能影响性能,考虑先缓存中间结果
  • Promise.all() 如果任一promise失败,整个都会失败,考虑使用 Promise.allSettled()

总结扩展

现代JavaScript的这些特性不仅让代码更简洁,还提供了很多强大的功能:

  • 使用新的数据结构(Map/Set)来处理复杂数据关系
  • 利用代理和反射实现更灵活的对象操作
  • 通过新的数组方法简化数据处理
  • 使用模块化特性组织更好的代码结构
  • 通过装饰器和私有字段实现更好的封装

建议:

  1. 循序渐进地在项目中引入新特性
  2. 注意浏览器兼容性,必要时使用Babel转译
  3. 关注性能影响,某些特性在大规模使用时可能影响性能
  4. 保持学习最新的提案和特性更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端切图仔001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值