Published on

ES6核心基础知识全解析(含语法特性、数据结构与深浅克隆)

一、变量声明:let/const与var的核心区别

ES6新增letconst声明变量,解决了var的作用域与提升问题,三者核心差异如下:

1.1 核心区别对比

特性varletconst
变量提升存在(提升后值为undefined)不存在(暂时性死区)不存在(暂时性死区)
全局属性挂载会挂载到window对象不会挂载到window对象不会挂载到window对象
重复声明允许(覆盖原值)不允许(语法错误)不允许(语法错误)
块级作用域无(函数/全局作用域)有(包裹区域)有(包裹区域)
重新赋值允许允许不允许(指向不可变)
初始值要求可选可选必须(声明即赋值)

1.2 关键注意点

  • const声明对象/数组时,仅限制“引用指向”不可变,对象内部属性/数组元素可修改;
  • 块级作用域应用:for(let i=0;i<5;i++)可避免循环中异步操作的变量污染问题。

二、解构赋值:快速提取数据的高效语法

解构赋值用于快速从数组/对象中提取数据,简化变量赋值操作,核心应用场景如下:

2.1 数组解构

// 基础解构
const [a, b, c] = [10, 20, 30]; // a=10, b=20, c=30

// 跳过元素
const [x, , y] = [10, 20, 30]; // x=10, y=30

// 剩余元素(扩展运算符)
const [first, ...rest] = [10, 20, 30, 40]; // first=10, rest=[20,30,40]

// 默认值
const [m, n = 0] = [5]; // m=5, n=0

// 变量交换
let p = 1, q = 2;
[p, q] = [q, p]; // p=2, q=1

2.2 对象解构

// 基础解构(变量名与属性名一致)
const { id, name } = { id: 1, name: '小米', age: 10 }; // id=1, name='小米'

// 别名解构(避免变量冲突)
const age = 0;
const { age: age1 } = { id: 1, name: '小米', age: 10 }; // age1=10

// 默认值
const { sex = '未知' } = { id: 1, name: '小米' }; // sex='未知'

// 嵌套解构
const data = [{ id: 1, name: '珠峰' }, { id: 2, name: '珠峰' }];
data.forEach(item => {
  const { id, name } = item || {};
  console.log(id, name);
});

三、扩展运算符与剩余运算符

...符号在不同场景下分别作为扩展运算符或剩余运算符,核心用法如下:

3.1 扩展运算符(展开数据)

  • 数组展开:用于数组克隆、合并或传递参数

    // 数组克隆(浅克隆)
    const arr1 = [10, 20, 30];
    const arr2 = [...arr1]; // arr2=[10,20,30], 与arr1互不影响(一级)
    
    // 数组合并
    const arr3 = [...arr1, 40, 50]; // [10,20,30,40,50]
    
  • 对象展开:用于对象合并、属性覆盖

    const obj1 = { a: 1 };
    const obj2 = { ...obj1, b: 2 }; // { a:1, b:2 }
    

3.2 剩余运算符(收集数据)

  • 函数参数:收集剩余参数为数组(替代arguments)
    const fn = (n, ...m) => {
      console.log(n); // 第一个参数
      console.log(m); // 剩余参数组成的数组
    };
    fn(10, 20, 30, 40); // n=10, m=[20,30,40]
    

四、数组新增方法与特性

ES6为数组新增多个实用方法,提升数据处理效率:

4.1 静态方法

  • Array.from():将类数组/Set集合转为数组

    const likeArr = document.querySelectorAll('div');
    const arr = Array.from(likeArr); // 转为真正的数组
    
  • Array.of():将一组值转为数组(修复new Array()的单参数缺陷)

    Array.of(1, 2, 3); // [1,2,3]
    Array.of(3); // [3](区别于new Array(3)生成长度为3的空数组)
    

4.2 实例方法

  • fill(value, start?, end?):填充数组元素

    new Array(3).fill(null); // [null, null, null]
    
  • includes(value):判断数组是否包含指定值(支持NaN)

    [1, 2, NaN].includes(NaN); // true(区别于indexOf,indexOf(NaN)返回-1)
    
  • flat(depth?):数组扁平化(默认深度为1)

    [1, [2, [3]]].flat(2); // [1,2,3]
    
  • entries()/keys()/values():返回迭代器对象,用于遍历数组

    for (const [index, value] of [10, 20].entries()) {
      console.log(index, value); // 0 10; 1 20
    }
    

五、新数据结构:Set与Map

ES6新增两种数据结构,解决传统数组/对象的局限性:

5.1 Set(无重复值的集合)

  • 核心特性:成员唯一,支持迭代,适合数组去重
  • 常用方法:
    // 数组去重
    const arr = [1, 1, 2, 3, 3];
    const uniqueArr = [...new Set(arr)]; // [1,2,3]
    
    // 基本操作
    const s = new Set();
    s.add(1).add(2); // 添加元素
    s.size; // 2(元素个数)
    s.has(1); // true(判断是否包含)
    s.delete(2); // true(删除元素)
    s.clear(); // 清空集合
    

5.2 Map(键可任意类型的键值对)

  • 核心特性:键可设为对象/数组等类型(区别于对象键仅为字符串/Symbol)
  • 常用方法:
    const m = new Map();
    const key = { x: 10 };
    
    // 基本操作
    m.set(key, 'value'); // 设置键值对(键为对象)
    m.get(key); // 'value'(获取值)
    m.size; // 1
    m.has(key); // true
    m.delete(key); // true
    
    // 遍历
    for (const [k, v] of m.entries()) {
      console.log(k, v);
    }
    

六、迭代器与生成器

6.1 迭代器(Iterator)

  • 本质:一种接口,为数据结构提供统一遍历机制,支持for...of循环
  • 原生支持迭代器的数据结构:Array、String、Set、Map、NodeList等
  • 自定义迭代器示例:
    const banji = {
      name: '终极一班',
      stus: ['xiaoming', 'xiaoning', 'xiaotian'],
      [Symbol.iterator]() {
        let index = 0;
        return {
          next: () => {
            if (index < this.stus.length) {
              return { value: this.stus[index++], done: false };
            } else {
              return { value: undefined, done: true };
            }
          }
        };
      }
    };
    
    // for...of遍历自定义迭代器
    for (const v of banji) {
      console.log(v); // xiaoming, xiaoning, xiaotian
    }
    

6.2 生成器(Generator)

  • 本质:异步编程解决方案,通过function*定义,yield分割代码执行

  • 核心用法:

    // 基本用法
    function* gen() {
      yield '第一步';
      yield '第二步';
      return '结束';
    }
    
    const iterator = gen();
    iterator.next(); // { value: '第一步', done: false }
    iterator.next(); // { value: '第二步', done: false }
    iterator.next(); // { value: '结束', done: true }
    
    // 带参数的生成器(next参数作为上一个yield的返回值)
    function* genWithParams(arg) {
      console.log(arg); // '初始参数'
      const one = yield '第一步';
      console.log(one); // '参数1'
      const two = yield '第二步';
      console.log(two); // '参数2'
    }
    
    const it = genWithParams('初始参数');
    it.next();
    it.next('参数1');
    it.next('参数2');
    
  • 异步场景应用(模拟分步数据获取):

    function getUsers() {
      setTimeout(() => iterator.next('用户数据'), 1000);
    }
    
    function* genAsync() {
      const users = yield getUsers();
      console.log(users); // 1秒后输出'用户数据'
    }
    
    const iterator = genAsync();
    iterator.next();
    

七、对象新增方法与特性

7.1 常用静态方法

方法作用示例
Object.assign(target, ...sources)合并对象(浅拷贝)Object.assign({a:1}, {b:2}){a:1,b:2}
Object.create(proto)创建新对象,指定原型Object.create({x:10}) → 新对象__proto__指向{x:10}
Object.entries(obj)返回对象键值对数组Object.entries({a:1})[['a',1]]
Object.is(a, b)精准比较两个值是否相等Object.is(NaN, NaN) → true
Object.freeze(obj)冻结对象(禁止修改属性)Object.freeze({a:1}) → 无法修改a的值

7.2 对象字面量增强

  • 属性简写:属性名与变量名一致时可省略

    const name = '小米';
    const obj = { name }; // 等价于{ name: name }
    
  • 方法简写:省略function关键字

    const obj = {
      sayHi() { console.log('hi'); } // 等价于sayHi: function(){}
    };
    

八、深浅克隆:对象/数组拷贝实现

8.1 浅克隆

  • 定义:仅拷贝第一级数据,引用类型仍共享堆地址
  • 实现方式:
    1. Object.assign()
    2. 扩展运算符([...arr]/{...obj}
    3. 数组slice()/concat()
    4. 自定义实现:
      function cloneShallow(obj) {
        const target = Array.isArray(obj) ? [] : {};
        for (const key in obj) {
          if (obj.hasOwnProperty(key)) {
            target[key] = obj[key];
          }
        }
        return target;
      }
      

8.2 深克隆

  • 定义:递归拷贝所有层级数据,引用类型创建新堆地址,修改互不影响
  • 实现方式:
    1. JSON方法(局限性:不支持函数、正则、循环引用)

      const deepCloneJSON = obj => JSON.parse(JSON.stringify(obj));
      
    2. 自定义实现(支持复杂类型与循环引用):

      function _type(obj) {
        return Object.prototype.toString.call(obj);
      }
      
      function deepClone(obj, map = new Map()) {
        // 处理null、基本类型、函数
        if (obj === null || typeof obj !== 'object') return obj;
      
        // 处理循环引用
        if (map.has(obj)) return map.get(obj);
      
        // 处理正则、日期
        if (_type(obj) === '[object RegExp]') return new RegExp(obj);
        if (_type(obj) === '[object Date]') return new Date(obj);
      
        // 创建同类型实例
        const target = new obj.constructor();
        map.set(obj, target); // 缓存当前对象,解决循环引用
      
        // 递归拷贝属性
        for (const key in obj) {
          if (obj.hasOwnProperty(key)) {
            target[key] = deepClone(obj[key], map);
          }
        }
      
        return target;
      }
      

九、核心总结

  1. 变量声明:优先使用let/const,避免var的作用域问题,const用于不可变引用;
  2. 数据提取:解构赋值简化数组/对象数据提取,配合扩展/剩余运算符提升效率;
  3. 数据结构:Set适合去重,Map适合非字符串键场景,替代传统数组/对象;
  4. 异步编程:生成器是ES6异步解决方案,通过yield分割代码,支持参数传递;
  5. 对象操作:掌握新增静态方法,深浅克隆需根据场景选择,复杂场景用自定义深克隆(处理循环引用)。

要不要我帮你整理一份 ES6核心语法实战代码手册,包含所有知识点的可直接运行示例与面试高频考点标注?