程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

Array.from() 的 5 个神仙用法,彻底告别 for 循环初始化!

balukai 2025-07-28 15:17:14 文章精选 6 ℃

在 JavaScript 中,当我们需要创建一个特定长度或内容的数组时,脑海里第一个闪过的念头可能就是 for 循环。

// 需求:创建一个长度为 5,内容为 [0, 1, 2, 3, 4] 的数组
const arr = [];
for (let i = 0; i < 5; i++) {
  arr.push(i);
}

这当然没问题,但有没有更优雅、更函数式的方式呢?

今天,就让我们来认识一下数组的“创造魔法师”——Array.from()。它不仅能将类数组对象和可迭代对象转换为真正的数组,其强大的第二个参数(一个 map 函数)更是能让我们玩出各种花样,彻底告别繁琐的 for 循环初始化。

用法一:创建数字序列(替代 for循环)

这是最基础也是最实用的一个用法。Array.from() 的第一个参数可以是一个具有 length 属性的对象。

// 需求:创建一个长度为 5,值为 [0, 1, 2, 3, 4] 的数组

// 老办法:for 循环
const arr1 = [];
for (let i = 0; i < 5; i++) { 
    arr1.push(i); 
}

// 神仙用法:Array.from()
const arr2 = Array.from({ length: 5 }, (value, index) => index);

console.log(arr2); // [0, 1, 2, 3, 4]

解析:

  1. { length: 5 }:我们创建了一个类似数组的对象,它只有 length 属性。
  2. (value, index) => index:这是 Array.from() 的第二个参数,一个映射函数。它会对新数组的每一个位置都执行一次。
  • index 是当前元素的索引 (0, 1, 2, 3, 4)。
  • value 在这种情况下是 undefined,因为 { length: 5 } 对象没有实际的值。
  • 我们直接返回 index 作为新数组元素的值。

就这样,一行代码就优雅地替代了整个 for 循环。

用法二:生成特定规则的数组

for 循环能做的,Array.from() 都能做得更漂亮。比如,生成一个由偶数组成的数组,或者一个平方数序列。

// 需求 1:创建一个包含 5 个偶数的数组 [0, 2, 4, 6, 8]
const evens = Array.from({ length: 5 }, (_, i) => i * 2);
console.log(evens); // [0, 2, 4, 6, 8]

// 需求 2:创建一个包含 1 到 5 的平方的数组 [1, 4, 9, 16, 25]
const squares = Array.from({ length: 5 }, (_, i) => (i + 1) ** 2);
console.log(squares); // [1, 4, 9, 16, 25]

// 需求 3:创建 5 个内容相同的元素
const fives = Array.from({ length: 5 }, () => 5);
console.log(fives); // [5, 5, 5, 5, 5]

技巧:如果我们在映射函数中用不到 value 参数,可以用下划线 _ 来占位,这是一种广为接受的代码风格,表示“这个参数我故意忽略了”。

用法三:快速初始化对象数组

在写测试用例或 mock 数据时,我们经常需要创建一组结构相同的对象。Array.from() 在这个场景下简直是神器。

// 需求:创建一个包含 3 个用户的数组,每个用户有 id 和一个随机分数
const users = Array.from({ length: 3 }, (_, i) => ({
    id: i + 1,
    score: Math.floor(Math.random() * 101) // 0-100 的随机分
}));

console.log(users);
/*
输出示例:
[
    { id: 1, score: 83 },
    { id: 2, score: 15 },
    { id: 3, score: 99 }
]
*/

一行代码,一个结构清晰、内容随机的对象数组就诞生了。是不是比写三遍 for 循环 push 一个对象要爽得多?

用法四:复制并深度处理数组

Array.from() 不仅能从零创建,还能基于现有数组进行“深加工”。它在转换的同时进行映射,一步到位,避免了先 mapfilter 等可能产生的中间数组。

const original = [1, '2', 3, null, '4', 5];

// 需求:从一个混合数组中,只提取出数字,并将非数字转为 0
// 返回 [1, 0, 3, 0, 0, 5]

const processed = Array.from(original, item => {
 const num = Number(item);
 return isNaN(num) ? 0 : num;
});

console.log(processed); // [1, 2, 3, 0, 4, 5]  <-- 修正:Number('2') 是 2,Number(null) 是 0
// Let's correct the example to be more illustrative
// 需求:将所有数字乘以2,非数字项保持为 null
const processedV2 = Array.from(original, item => {
    return typeof item === 'number' ? item * 2 : null;
});
console.log(processedV2); // [2, null, 6, null, null, 10]

对比 map:

Array.from(array, mapFn) 的效果和 array.map(mapFn) 几乎一样。但 Array.from 的优势在于它的第一个参数可以是类数组对象

比如,处理函数的 arguments 对象或者 DOM 查询结果 NodeList

function sumArguments() {
    // arguments 是一个类数组对象,它没有 .map 方法
    // return arguments.map(x => x * 2); // Uncaught TypeError: arguments.map is not a function

    // 用 Array.from 就可以轻松处理
    const argsArray = Array.from(arguments);
    return argsArray.reduce((sum, num) => sum + num, 0);
}

console.log(sumArguments(1, 2, 3, 4)); // 10

用法五:巧妙生成字母序列

谁说只能处理数字?Array.from() 结合字符编码,可以轻松生成字母表。

// 需求:生成一个从 'A' 到 'Z' 的字母数组

const alphabet = Array.from({ length: 26 }, (_, i) => {
  // 'A' 的 ASCII 码是 65
  return String.fromCharCode(65 + i);
});

console.log(alphabet);
// ["A", "B", "C", ..., "Z"]

这个用法虽然不常用,但它绝佳地展示了 Array.from() 的灵活性和表现力,是面试中展示我们技术深度的小亮点。

最近发表
标签列表