Skip to content

JS执行速度优化

这是关于JavaScript刷算法题提高执行速度、降低执行时间的技巧分享

在 JavaScript 中刷力扣算法题时,执行时间受代码细节、数据结构选择和语言特性影响较大。以下是经过实践验证的 10 个降低执行时间的核心技巧,结合具体场景说明:

1. for 循环替代数组方法(forEach/map/filter

  • 原因forEach 等方法本质是函数调用,每次迭代会创建函数作用域,存在额外开销;for 循环是原生语法,执行效率更高。
  • 场景:大规模数组遍历(如长度 > 10000)。
  • 示例
    javascript
    // 较慢
    let sum = 0;
    arr.forEach(num => sum += num);
    
    // 更快
    let sum = 0;
    for (let i = 0; i < arr.length; i++) {
      sum += arr[i];
    }

对比for...of

  • 传统 for 循环是最基础的迭代方式,通过索引直接访问元素(如 nums[i]),逻辑简单,JavaScript 引擎(如 V8)对其优化程度最高(可进行循环展开、边界检查消除等底层优化)。
  • for...of 循环基于迭代器协议,需要创建迭代器对象、调用 next() 方法、检查 done 属性等额外操作,这些会产生微小的性能开销,累积后在大数据量场景中会拉开差距。

2. 缓存数组长度,避免重复计算

  • 原因for 循环中每次判断 i < arr.length 时,都会重新计算数组长度(尤其对于动态数组),缓存后可减少操作。
  • 场景:任何 for 循环遍历。
  • 示例
    javascript
    // 较慢
    for (let i = 0; i < arr.length; i++) { ... }
    
    // 更快
    for (let i = 0, len = arr.length; i < len; i++) { ... }

3. 优先使用 Map/Set 优化查找效率

  • 原因:数组的 indexOf/includes 是 O(n) 复杂度,而 MaphasSethas 是 O(1)。
  • 场景:需要频繁判断“元素是否存在”(如两数之和、去重)。
  • 示例
    javascript
    // 较慢(O(n²))
    function findTarget(arr, target) {
      for (let i = 0; i < arr.length; i++) {
        if (arr.includes(target - arr[i]) && ...) { ... }
      }
    }
    
    // 更快(O(n))
    function findTarget(arr, target) {
      const map = new Map();
      for (let i = 0; i < arr.length; i++) {
        if (map.has(target - arr[i])) { ... }
        map.set(arr[i], i);
      }
    }

4. 避免不必要的变量复制和引用类型操作

  • 原因:对象/数组的复制(如 slice、扩展运算符 ...)会创建新内存,耗时随数据量增长。
  • 场景:原地修改数组(如排序、覆盖元素)。
  • 示例
    javascript
    // 较慢(复制数组)
    const newArr = arr.slice();
    newArr.sort((a, b) => a - b);
    
    // 更快(原地排序)
    arr.sort((a, b) => a - b); // 直接修改原数组

5. while 循环处理高频迭代场景

  • 原因while 循环的语法解析开销略低于 for 循环,在极端高频迭代(如百万级)时更优。
  • 场景:数值计算(如斐波那契、阶乘)、链表遍历。
  • 示例
    javascript
    // 计算 n 的阶乘(while 比 for 略快)
    function factorial(n) {
      let res = 1;
      while (n > 1) {
        res *= n;
        n--;
      }
      return res;
    }

6. 减少全局变量访问,优先使用局部变量

  • 原因:JavaScript 查找变量时,全局作用域比局部作用域层级更深,访问耗时更长。
  • 场景:函数内频繁使用的变量(如循环计数器、中间结果)。
  • 示例
    javascript
    // 较慢(全局变量)
    let globalSum = 0;
    function sumArr(arr) {
      for (let i = 0; i < arr.length; i++) {
        globalSum += arr[i]; // 每次访问全局变量
      }
    }
    
    // 更快(局部变量)
    function sumArr(arr) {
      let localSum = 0; // 局部变量
      for (let i = 0; i < arr.length; i++) {
        localSum += arr[i];
      }
      return localSum;
    }

7. 利用位运算替代数学运算

  • 原因:位运算直接操作二进制,比算术运算(如乘除、取模)更快。
  • 场景:整数除以 2(n >> 1)、判断奇偶(n & 1)、取模 2^k 等。
  • 示例
    javascript
    // 较慢
    const half = n / 2;
    const isOdd = n % 2 === 1;
    
    // 更快
    const half = n >> 1; // 等价于 Math.floor(n / 2)
    const isOdd = (n & 1) === 1;

8. 避免字符串拼接的低效操作

  • 原因:字符串在 JavaScript 中是不可变的,每次 + 拼接都会创建新字符串,复杂度 O(n²)。
  • 场景:大量字符串拼接(如拼接数组元素)。
  • 优化方案:用 Array.join('') 替代 +,因为数组可以原地修改,最后一次性拼接。
    javascript
    // 较慢
    let str = '';
    for (let i = 0; i < 10000; i++) {
      str += i; // 每次创建新字符串
    }
    
    // 更快
    const arr = [];
    for (let i = 0; i < 10000; i++) {
      arr.push(i);
    }
    const str = arr.join(''); // 一次拼接

9. 提前处理边界条件,减少无效计算

  • 原因:在循环或递归前判断边界(如空数组、0/1 等特殊值),可避免不必要的执行。
  • 场景:数组/链表操作、递归函数(如斐波那契、二叉树遍历)。
  • 示例
    javascript
    // 较慢(进入循环后才判断)
    function sumArr(arr) {
      let sum = 0;
      for (let i = 0; i < arr.length; i++) {
        sum += arr[i];
      }
      return sum;
    }
    
    // 更快(提前退出)
    function sumArr(arr) {
      if (arr.length === 0) return 0; // 边界条件优先
      let sum = 0;
      for (let i = 0, len = arr.length; i < len; i++) {
        sum += arr[i];
      }
      return sum;
    }

10. 用 typedArray 处理大量数值数据

  • 原因:普通数组可以存储任意类型,而 TypedArray(如 Uint32Array)仅存储特定类型的数值,内存占用更少,访问速度更快。
  • 场景:图像处理、大规模数值计算(如前缀和、滑动窗口)。
  • 示例
    javascript
    // 处理大量整数时,TypedArray 比普通数组快
    const nums = new Uint32Array(1000000); // 仅存 32 位无符号整数
    for (let i = 0; i < nums.length; i++) {
      nums[i] = i; // 赋值和访问更快
    }

总结

JavaScript 优化的核心是 “减少不必要的开销”

  • 用高效语法(for/while 替代函数式方法);
  • 选对数据结构(Map/Set 优化查找);
  • 避免冗余操作(全局变量、重复复制)。

实际刷题时,先保证算法复杂度最优(如 O(n) 优于 O(n²)),再用上述技巧优化常数时间,执行效率会显著提升。