这段代码展示了 JavaScript 中 apply
方法的一个经典用法,用于将一个类数组对象(array-like object)转换为真正的数组。让我逐步拆解并解释这段代码的工作原理。
代码
1 2 |
const arrayLike = { 0: "apple", 1: "banana", length: 2 }; const realArray = Array.prototype.slice.apply(arrayLike); |
逐行解释
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
等)。
- 在 JavaScript 中,类数组对象是指具有数字索引属性(如
- 当前值:
1 2 3 4 5 |
arrayLike = { 0: "apple", 1: "banana", length: 2 } |
2. const realArray = Array.prototype.slice.apply(arrayLike);
这行代码的目标是将 arrayLike
转换为真正的数组。分解来看:
(1) Array.prototype.slice
slice
方法:- 是数组的内置方法,用于从数组中截取一部分并返回新数组。
- 语法:
array.slice(start, end)
,不传参数时返回整个数组的浅拷贝。 - 示例:
12const arr = ["a", "b", "c"];console.log(arr.slice()); // ["a", "b", "c"]
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"]
。
- 结果:
1 |
realArray = ["apple", "banana"]; |
为什么这样做?
- 目的:将类数组对象转为真正的数组,以便使用数组方法。
- 为什么用
apply
:arrayLike
本身没有slice
方法(它不是数组)。- 通过
apply
,我们“借用”了数组的slice
方法,并将arrayLike
作为this
传入。
- 历史背景:
- 在 ES5 及更早版本中,这是将类数组转为数组的常见技巧。
- ES6 后可以用
Array.from(arrayLike)
或[...arrayLike]
,更简洁。
等价代码
以下是现代等价的写法,效果相同:
- 使用
Array.from
:
1 |
const realArray = Array.from(arrayLike); |
- 使用扩展运算符:
1 |
const realArray = [...arrayLike]; |
但在这段代码中,展示了 apply
的经典用法,理解它有助于掌握 JavaScript 的底层机制。
验证结果
1 2 3 |
console.log(realArray); // ["apple", "banana"] console.log(Array.isArray(realArray)); // true(是真正的数组) console.log(Array.isArray(arrayLike)); // false(不是数组) |
深入理解
slice
的行为:
slice
不关心this
是否真的是数组,只要有length
和数字索引,它就能工作。- 如果
length
缺失或不正确,结果可能不准确:12const broken = { 0: "x", 1: "y" }; // 无 lengthconsole.log(Array.prototype.slice.apply(broken)); // []
apply
的灵活性:
- 可以传递参数给
slice
,比如:
1const partial = Array.prototype.slice.apply(arrayLike, [1]); // ["banana"]
- 与
call
的区别:
- 如果用
call
,需要逐个传递参数:
1const realArray = Array.prototype.slice.call(arrayLike); // 同样是 ["apple", "banana"] apply
用数组传递参数,适合动态参数场景。
总结
- 含义:这段代码借用
Array.prototype.slice
方法,通过apply
将类数组arrayLike
转为真正的数组。 - 过程:
arrayLike
提供数据(0
,1
,length
)。apply
将slice
的this
绑定到arrayLike
。slice
根据length
提取索引值,生成新数组。
- 结果:
realArray
是["apple", "banana"]
。 - 意义:展示了
apply
的“方法借用”能力,是 JavaScript 函数式编程的基础技巧之一。