Article 十一月 28, 2020

深度剖析为什么 [].slice.call() 能将 NodeList 转为数组

Words count 2.5k Reading time 2 mins. Read count 0

前言

js中有不少比较难以理解的概念,比如 js原型继承 。我曾经很早的时候就看过js原型方面的知识,并在当时写了一篇 博客 作为记录,很显然当时的我只是死记硬背。最近我利用空闲的时间将一些相对比较深入的js概念和用法重新学习,并新建了一个专栏 深入javascript 用于记录和分享。以下来剖析 为什么 [].slice.call() 能将 NodeList 转为数组

概念

在剖析之前需要了解一些概念:

伪数组也叫类数组,它无法直接调用数组方法或期望length属性有什么特殊的行为,但仍可以用真正数组遍历方法来遍历它们。典型的是函数的argument参数,还有像调用 querySelectorAll 返回的NodeList对象都属于伪数组。

数组的 slice 基础语法是 array.slice(start, end) 更具体用法不多赘述,以下用一段代码探索它的默认行为:

const arr = [1, 2, 3, 4, 5]

arr.slice(0, arr.length)    // [1, 2, 3, 4, 5]

arr.slice()    // [1, 2, 3, 4, 5]

从以上的代码结果可以看出,slice 方法 start 参数默认值是 0,end 参数默认值是 slice 调用者的 length

实现一个简单的 slice 方法

<ul>
    <li>F</li>
    <li>O</li>
    <li>O</li>
</ul>

<script>
    Array.prototype.slice2 = function (start = 0, end = this.length) {
        console.log(`打印看看当前的 this: ${this}`)    // [object NodeList]
        const result = []
        for (let i = start; i < end; i++) {
            result.push(this[i])
        }
        return result
    };

    // 试一试效果
    const nodeArr = [].slice2.call(document.querySelectorAll('li'))    // [li, li, li]
    const nodeArr2 = [].slice2.call(document.querySelectorAll('li'), 0, 2) // [li, li]
</script>

上面的一段引用介绍了 伪数组 是可以被 for 循环的,在以上的代码中我们分别定义了 起始点 start结束点 end 将一段指定区间内的 NodeList 子元素 push 到一个新数组中,从而将 伪数组 转换成了 Array 。它得以操作 length 属性改变数组元素个数、可以使用数组的各个方法了。

总结

[].slice2.call(NodeList)NodeList 转为 数组的方法在我的职业生涯中至少用过数次,但之前几乎每次想要使用时都得搜索一下,得其结果完成项目草草了事,每每不得其义。但真正的静下心来去探索它的原理,发现原来如此简单。虽然现在有更简单的方式将 NodeList 转为数组 [...document.querySelectorAll('li')] ,但是花点时间研究一下js中深入的东西,真的很有意思。

0%