本文详细解析 JavaScript 中 Array.from() 方法的多种应用场景。涵盖将类数组对象和可遍历对象(如 Set、Map、字符串)转换为真实数组,利用第二个参数实现类似 map 的映射处理,以及通过第三个参数绑定 this 上下文。此外,还介绍了该方法在计算包含 Unicode 字符的字符串长度时的优势,以及在不支持该方法的浏览器中的 Polyfill 方案。
Array.from 基础概念与对象转换
Array.from 方法主要用于将两类对象转换为真正的数组:一类是类似数组的对象(array-like object),另一类是可遍历(iterable)的对象,其中包括 ES6 新增的 Set 和 Map 数据结构。
以下示例展示了一个类似数组的对象,通过 Array.from 可以将其转换为真正的数组。
类数组对象转换示例
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
在实际开发中,常见的类似数组对象包括 DOM 操作返回的 NodeList 集合,以及函数内部的 arguments 对象。Array.from 方法均能将这些对象成功转换为真正的数组。
DOM 节点与 arguments 对象处理
// NodeList对象
let ps = document.querySelectorAll('p');
Array.from(ps).filter(p => {
return p.textContent.length > 100;
});
// arguments对象
function foo() {
var args = Array.from(arguments);
// ...
}
上述代码中,querySelectorAll 方法返回的是一个类似数组的对象。利用 Array.from 将其转换为真正的数组后,即可直接使用 filter 方法进行过滤处理。
任何部署了 Iterator 接口的数据结构,都可以被 Array.from 方法转换为数组。
可遍历对象(Set/字符串)转换
Array.from('hello')
// ['h', 'e', 'l', 'l', 'o']
let namesSet = new Set(['a', 'b'])
Array.from(namesSet) // ['a', 'b']
在上面的代码示例中,字符串和 Set 结构均具备 Iterator 接口,因此可以直接通过 Array.from 转换为真正的数组。
如果传入的参数本身就是一个真正的数组,Array.from 会返回一个与原数组内容完全一致的新数组。
真数组的浅拷贝特性
Array.from([1, 2, 3])
// [1, 2, 3]
值得注意的是,扩展运算符(...)也能将某些数据结构转换为数组。
扩展运算符与 Array.from 的区别
// arguments对象
function foo() {
const args = [...arguments];
}
// NodeList对象
[...document.querySelectorAll('div')]
扩展运算符底层调用的是遍历器接口(Symbol.iterator)。若对象未部署该接口,则无法通过扩展运算符转换。相比之下,Array.from 方法还支持类似数组的对象。所谓类似数组的对象,其核心特征仅有一点:必须拥有 length 属性。因此,任何具备 length 属性的对象均可通过 Array.from 转换为数组,而扩展运算符在此场景下则无法实现转换。
具备 length 属性的对象转换
Array.from({ length: 3 });
// [ undefined, undefined, undefined ]
上述代码中,Array.from 返回了一个包含三个成员的数组,每个位置的值均为 undefined。扩展运算符无法对此类对象进行转换。
对于尚未支持该方法的浏览器,可以使用 Array.prototype.slice 方法作为替代方案。
浏览器兼容性 Polyfill 方案
const toArray = (() =>
Array.from ? Array.from : obj => [].slice.call(obj)
)();
Array.from 还可以接受第二个参数,其作用类似于数组的 map 方法,用于对每个元素进行预处理,并将处理后的值放入返回的数组中。
第二个参数:映射处理功能
Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);
Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]
下面的示例展示了如何提取一组 DOM 节点的文本内容。
提取 DOM 节点文本内容
let spans = document.querySelectorAll('span.name');
// map()
let names1 = Array.prototype.map.call(spans, s => s.textContent);
// Array.from()
let names2 = Array.from(spans, s => s.textContent)
以下示例演示了如何将数组中布尔值为 false 的成员转换为 0。
数组元素过滤与转换
Array.from([1, , 2, , 3], (n) => n || 0)
// [1, 0, 2, 0, 3]
另一个示例用于返回各种数据的类型。
获取数据类型的示例
function typesOf () {
return Array.from(arguments, value => typeof value)
}
typesOf(null, [], NaN)
// ['object', 'object', 'number']
如果 map 函数内部使用了 this 关键字,可以通过传入 Array.from 的第三个参数来绑定 this 指向。
Array.from() 能够将各种值转换为真正的数组,并提供 map 功能。这意味着,只要存在原始数据结构,就可以先对其值进行处理,再转换为规范的数组结构,从而使用数量丰富的数组方法。
高级用法:this 绑定与灵活应用
Array.from({ length: 2 }, () => 'jack')
// ['jack', 'jack']
上述代码中,Array.from 的第一个参数指定了第二个参数运行的次数。这一特性使得该方法的用法更加灵活。
Array.from() 的另一个应用场景是将字符串转换为数组,进而返回字符串的长度。由于它能正确处理各种 Unicode 字符,因此可以避免 JavaScript 将大于 \uFFFF 的 Unicode 字符错误地计算为两个字符的 bug。
计算 Unicode 字符串长度
function countSymbols(string) {
return Array.from(string).length;
}本文关于 JavaScript 中 Array.from() 的完整用法解析到此结束。如需了解更多相关 JavaScript Array.from 内容,请搜索本站历史文章或继续浏览后续相关文章,感谢大家的支持!