基础 | 🔥ES6三剑客:let/const/var谁主沉浮?🤯

%% 变量声明特性对比 flowchart TD subgraph 变量声明方式 A[var] C[let] E[const] end A --> B[函数作用域
可重复声明
变量提升] C --> D[块级作用域
不可重复声明
暂时性死区] E --> F[块级作用域
必须初始化
引用不可变] classDef keyword fill:#ffeaa7,stroke:#d63031 class A,C,E keyword

ES6核心功能概览

ES6(ECMAScript 2015)是JavaScript发展史上的重要里程碑,带来了众多革命性特性:

🎯主要功能列表

  • let/const 变量声明
  • 箭头函数 =>
  • 模板字符串 Hello ${name}
  • 解构赋值 [a, b] = [1, 2]
  • 默认参数 function(a = 1)
  • 扩展运算符 ...array
  • Promise异步处理
  • Class类语法
  • Module模块系统
  • Set/Map数据结构

🆚 let、const 与 var 的区别

📊详细对比表格

特性 var let const
作用域 函数作用域 块级作用域 块级作用域
变量提升 是(undefined) 是(暂时性死区) 是(暂时性死区)
重复声明 允许 ❌禁止 ❌禁止
重新赋值 ✅允许 ✅允许 ❌禁止
初始化 可选 可选 必须

💥实际代码演示

javascript 复制代码
function scopeTest() {
  // var 的函数作用域
  if (true) {
    var a = 1;
    let b = 2;
    const c = 3;
  }
  console.log(a); // 1 - 可访问
  // console.log(b); // ReferenceError
  // console.log(c); // ReferenceError
  
  // 重复声明问题
  var name = 'Jake';
  var name = 'Tom'; // ✅ 允许
  // let age = 20;
  // let age = 25; // ❌ SyntaxError
}

// 暂时性死区示例
function temporalDeadZone() {
  // console.log(x); // ReferenceError
  let x = 1;
}

📋浅拷贝 vs 深拷贝

🎯核心区别

浅拷贝 :只复制对象的第一层属性,嵌套对象仍指向同一内存地址
深拷贝:递归复制对象的所有层级,完全独立的新对象

💻实现代码对比

javascript 复制代码
// 浅拷贝实现
function shallowCopy(obj) {
  if (typeof obj !== 'object' || obj === null) return obj;
  const result = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      result[key] = obj[key]; // 直接赋值引用
    }
  }
  return result;
}

// 深拷贝实现(简化版)
function deepCopy(obj, map = new WeakMap()) {
  if (typeof obj !== 'object' || obj === null) return obj;
  if (map.has(obj)) return map.get(obj); // 处理循环引用
  
  const result = Array.isArray(obj) ? [] : {};
  map.set(obj, result); // 记录已拷贝对象
  
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      result[key] = deepCopy(obj[key], map); // 递归拷贝
    }
  }
  return result;
}

// 测试用例
const original = {
  name: 'Jake',
  skills: ['JS', 'CSS'],
  address: { city: 'Beijing' }
};

const shallow = shallowCopy(original);
const deep = deepCopy(original);

original.skills.push('React');
console.log(shallow.skills); // ['JS', 'CSS', 'React'] - 被影响
console.log(deep.skills);    // ['JS', 'CSS'] - 不受影响

⚡快速排序算法详解

🎯算法原理

快速排序采用"分治法"思想:

  1. 选择一个基准元素(pivot)
  2. 将数组分为两部分:小于基准的放左边,大于基准的放右边
  3. 递归处理左右两部分

💻核心实现

javascript 复制代码
function quickSort(arr) {
  if (arr.length <= 1) return arr;
  
  const pivotIndex = Math.floor(arr.length / 2);
  const pivot = arr[pivotIndex];
  const left = [];
  const right = [];
  
  for (let i = 0; i < arr.length; i++) {
    if (i === pivotIndex) continue; // 跳过基准元素
    if (arr[i] < pivot) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }
  
  // 递归排序并合并结果
  return [...quickSort(left), pivot, ...quickSort(right)];
}

// 测试
const arr = [64, 34, 25, 12, 22, 11, 90];
console.log(quickSort(arr)); // [11, 12, 22, 25, 34, 64, 90]

📊时间复杂度分析

  • 最好情况:O(n log n) - 每次都能均匀分割
  • 最坏情况:O(n²) - 每次选到最大或最小元素作为基准
  • 平均情况:O(n log n)

🏆前K个最大元素算法

🎯问题描述

给定一个数组,找出其中前K个最大的元素

💻多种解法对比

javascript 复制代码
// 方法1: 排序后取前K个 - 时间复杂度 O(n log n)
function topKBySort(nums, k) {
  return nums.sort((a, b) => b - a).slice(0, k);
}

// 方法2: 最小堆 - 时间复杂度 O(n log k)
class MinHeap {
  constructor() {
    this.heap = [];
  }
  
  push(val) {
    this.heap.push(val);
    this.up(this.heap.length - 1);
  }
  
  pop() {
    if (this.heap.length === 1) return this.heap.pop();
    const top = this.heap[0];
    this.heap[0] = this.heap.pop();
    this.down(0);
    return top;
  }
  
  up(index) {
    while (index > 0) {
      const parentIndex = Math.floor((index - 1) / 2);
      if (this.heap[parentIndex] <= this.heap[index]) break;
      [this.heap[parentIndex], this.heap[index]] = 
        [this.heap[index], this.heap[parentIndex]];
      index = parentIndex;
    }
  }
  
  down(index) {
    const lastIndex = this.heap.length - 1;
    while (true) {
      let minIndex = index;
      const leftIndex = index * 2 + 1;
      const rightIndex = index * 2 + 2;
      
      if (leftIndex <= lastIndex && 
          this.heap[leftIndex] < this.heap[minIndex]) {
        minIndex = leftIndex;
      }
      if (rightIndex <= lastIndex && 
          this.heap[rightIndex] < this.heap[minIndex]) {
        minIndex = rightIndex;
      }
      
      if (minIndex === index) break;
      [this.heap[index], this.heap[minIndex]] = 
        [this.heap[minIndex], this.heap[index]];
      index = minIndex;
    }
  }
  
  size() { return this.heap.length; }
  top() { return this.heap[0]; }
}

function topKByHeap(nums, k) {
  const heap = new MinHeap();
  
  for (const num of nums) {
    heap.push(num);
    if (heap.size() > k) {
      heap.pop(); // 弹出最小值,保持堆大小为k
    }
  }
  
  return heap.heap.sort((a, b) => b - a); // 降序返回
}

// 测试用例
const nums = [3, 2, 1, 5, 6, 4];
const k = 2;
console.log(topKBySort(nums, k)); // [6, 5]
console.log(topKByHeap(nums, k)); // [6, 5]

Q1: 为什么说const更安全?

A1: const声明的变量不能被重新赋值,避免了意外修改,特别是在复杂对象中保护引用不被改变 😱

Q2: 深拷贝如何处理循环引用?

A2: 使用WeakMap记录已拷贝的对象,再次遇到时直接返回引用,避免无限递归 💥

Q3: 快排的基准元素选择有什么讲究?

A3: 随机选择或三数取中法可以避免最坏情况,提升平均性能 🎯

Q4: 堆排序和快排哪个更适合找TopK?

A4: 堆排序更适合,时间复杂度稳定为O(n log k),而快排平均O(n)但最坏O(n²)

Q5: ES6的解构赋值在实际项目中有哪些妙用?

A5: 函数参数解构、数组交换、对象属性提取等,代码更简洁易读 🚀

相关推荐
苏格拉没有底了36 分钟前
由频繁创建3D火焰造成的内存泄漏问题
前端
阿彬爱学习37 分钟前
大模型在垂直场景的创新应用:搜索、推荐、营销与客服新玩法
前端·javascript·easyui
我是哪吒41 分钟前
分布式微服务系统架构第164集:架构懂了就来了解数据库存储扩展千亿读写
后端·面试·github
UrbanJazzerati1 小时前
PowerShell 自动化实战:自动化为 Git Staged 内容添加 Issue 注释标记
后端·面试·shell
橙序员小站1 小时前
通过trae开发你的第一个Chrome扩展插件
前端·javascript·后端
Lazy_zheng1 小时前
一文掌握:JavaScript 数组常用方法的手写实现
前端·javascript·面试
是晓晓吖1 小时前
关于Chrome Extension option的一些小事
前端·chrome
wave7771 小时前
feign的bean创建过程-底层请求过程-源码走读
后端·面试
MrSkye1 小时前
🔥从菜鸟到高手:彻底搞懂 JavaScript 事件循环只需这一篇(下)
前端·javascript·面试
方佑1 小时前
✨ Nuxt 混合渲染实践: MemOS前端体验深度优化指南
前端