Array.prototype.slice.apply将类数组对象转换为数组的工作原理

这段代码展示了 JavaScript 中 apply 方法的一个经典用法,用于将一个类数组对象(array-like object)转换为真正的数组。让我逐步拆解并解释这段代码的工作原理。


代码


逐行解释

1. const arrayLike = { 0: "apple", 1: "banana", length: 2 };

  • 定义arrayLike 是一个普通对象,但它的结构模仿了数组,具有以下特点:
    • 数字键01 是属性名,对应值 "apple""banana"
    • length 属性:值为 2,表示这个对象“像”一个长度为 2 的数组。
  • 类数组对象
    • 在 JavaScript 中,类数组对象是指具有数字索引属性(如 0, 1, …)和 length 属性的对象。
    • 常见的类数组包括 arguments 对象、DOM 节点列表(如 document.querySelectorAll 的结果)等。
    • 但它不是真正的数组,因此没有数组的方法(如 pushslice 等)。
  • 当前值

2. const realArray = Array.prototype.slice.apply(arrayLike);

这行代码的目标是将 arrayLike 转换为真正的数组。分解来看:

(1) Array.prototype.slice
  • slice 方法
    • 是数组的内置方法,用于从数组中截取一部分并返回新数组。
    • 语法:array.slice(start, end),不传参数时返回整个数组的浅拷贝。
    • 示例:
  • Array.prototype
    • Array.prototype.sliceslice 方法的原始定义,可以被借用。
    • 所有数组实例都继承自 Array.prototype,它是数组方法的来源。
(2) .apply(arrayLike)
  • apply 方法
    • 是函数对象的方法,用于调用函数并指定 this 和参数。
    • 语法:function.apply(thisArg, [argsArray])
    • 这里:
      • thisArgarrayLike,将 slicethis 绑定到 arrayLike
      • argsArray:未提供,默认是 undefined,相当于调用 slice() 没有参数。
  • 作用
    • applyArray.prototype.slicearrayLike 上执行。
    • slice 会读取 this(即 arrayLike)的 length 属性和数字索引属性(0, 1, …),然后返回一个新数组。
(3) 执行过程
  • Array.prototype.slicearrayLike 上执行时:
    • slice 检查 this.length,发现是 2
    • this[0]this[length - 1] 依次取值:
      • this[0]"apple"
      • this[1]"banana"
    • 返回一个新数组:["apple", "banana"]
  • 结果

为什么这样做?

  • 目的:将类数组对象转为真正的数组,以便使用数组方法。
  • 为什么用 apply
    • arrayLike 本身没有 slice 方法(它不是数组)。
    • 通过 apply,我们“借用”了数组的 slice 方法,并将 arrayLike 作为 this 传入。
  • 历史背景
    • 在 ES5 及更早版本中,这是将类数组转为数组的常见技巧。
    • ES6 后可以用 Array.from(arrayLike)[...arrayLike],更简洁。

等价代码

以下是现代等价的写法,效果相同:

  1. 使用 Array.from
  1. 使用扩展运算符:

但在这段代码中,展示了 apply 的经典用法,理解它有助于掌握 JavaScript 的底层机制。


验证结果


深入理解

  1. slice 的行为
  • slice 不关心 this 是否真的是数组,只要有 length 和数字索引,它就能工作。
  • 如果 length 缺失或不正确,结果可能不准确:
  1. apply 的灵活性
  • 可以传递参数给 slice,比如:
  1. call 的区别
  • 如果用 call,需要逐个传递参数:
  • apply 用数组传递参数,适合动态参数场景。

总结

  • 含义:这段代码借用 Array.prototype.slice 方法,通过 apply 将类数组 arrayLike 转为真正的数组。
  • 过程
  1. arrayLike 提供数据(0, 1, length)。
  2. applyslicethis 绑定到 arrayLike
  3. slice 根据 length 提取索引值,生成新数组。
  • 结果realArray["apple", "banana"]
  • 意义:展示了 apply 的“方法借用”能力,是 JavaScript 函数式编程的基础技巧之一。