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

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


代码


逐行解释

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

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

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

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

(1) Array.prototype.slice
  • slice 方法:
    • 是数组的内置方法,用于从数组中截取一部分并返回新数组。
    • 语法:array.slice(start, end),不传参数时返回整个数组的浅拷贝。
    • 示例:
  • Array.prototype:
    • Array.prototype.slice 是 slice 方法的原始定义,可以被借用。
    • 所有数组实例都继承自 Array.prototype,它是数组方法的来源。
(2) .apply(arrayLike)
  • apply 方法:
    • 是函数对象的方法,用于调用函数并指定 this 和参数。
    • 语法:function.apply(thisArg, [argsArray])。
    • 这里:
      • thisArg:arrayLike,将 slice 的 this 绑定到 arrayLike。
      • argsArray:未提供,默认是 undefined,相当于调用 slice() 没有参数。
  • 作用:
    • apply 让 Array.prototype.slice 在 arrayLike 上执行。
    • slice 会读取 this(即 arrayLike)的 length 属性和数字索引属性(0, 1, …),然后返回一个新数组。
(3) 执行过程
  • 当 Array.prototype.slice 在 arrayLike 上执行时:
    • 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. apply 将 slice 的 this 绑定到 arrayLike。
  3. slice 根据 length 提取索引值,生成新数组。
  • 结果:realArray 是 ["apple", "banana"]。
  • 意义:展示了 apply 的“方法借用”能力,是 JavaScript 函数式编程的基础技巧之一。