我偶然发现了一个将DOM NodeList转换为常规数组的巧妙快捷方式,但我必须承认,我并不完全理解它是如何工作的:
[].slice.call(document.querySelectorAll('a'), 0)
它从一个空数组[]
开始,然后使用slice
将call
的结果转换为一个新数组,对吧?
我不理解的部分是call
。它如何将document.querySelectorAll('a')
从NodeList转换为普通数组?
我偶然发现了一个将DOM NodeList转换为常规数组的巧妙快捷方式,但我必须承认,我并不完全理解它是如何工作的:
[].slice.call(document.querySelectorAll('a'), 0)
它从一个空数组[]
开始,然后使用slice
将call
的结果转换为一个新数组,对吧?
我不理解的部分是call
。它如何将document.querySelectorAll('a')
从NodeList转换为普通数组?
call()
将slice()
作为NodeList
的函数进行调用。在这种情况下,slice()
创建一个空数组,然后遍历它所运行的对象(最初是一个数组,现在是NodeList
)并将该对象的元素附加到它所创建的空数组中,最终返回的就是该数组。这是一篇关于此问题的文章:article on this。
编辑:
那不对。因此,它从一个空数组[]开始,然后使用slice将调用结果转换为新数组,对吗?
[].slice
返回一个函数对象。函数对象具有一个函数call()
,该函数调用将第一个参数分配给this
的函数; 换句话说,使函数认为它是从参数(由document.querySelectorAll('a')
返回的NodeList
)而不是从数组调用的。Array.prototype.slice.call(...)
在语义上等效,但它实际上只是实例化一个数组对象([]
)来访问其原型切片方法。这是一种浪费的实例化。相反,如果您在计算字符数,则可以使用Array.prototype.slice.call(...)
,这样更加简洁。 - Ben Zotto[]
比Array
更可靠,因为Array
可能被覆盖成其他内容。如果需要重复使用Array#slice
,建议进行缓存。 - Mathias Bynensvar array = []; var push = array.push; var slice = array.slice; var splice = array.splice;
他这样做是为了@MathiasBynens提到的安全问题吗? - owensmartin在JavaScript中,对象的方法可以在运行时绑定到另一个对象。简而言之,JavaScript允许一个对象“借用”另一个对象的方法:
object1 = {
name: 'Frank',
greet() {
alert(`Hello ${this.name}`);
}
};
object2 = {
name: 'Andy'
};
// Note that object2 has no greet method,
// but we may "borrow" from object1:
object1.greet.call(object2); // Will show an alert with 'Hello Andy'
call
和 apply
方法可以让你在 JavaScript 中对函数对象(在 JavaScript 中,函数本身也是对象)进行这样的操作。 因此,在您的代码中,您可以说 NodeList 借用了数组的 slice 方法。.slice()
返回另一个数组作为其结果,这将成为您可以使用的“转换”数组。Array.prototype
或者 [].prototype
的 call
函数。 - Sourabh它从一个Array
中检索slice
函数。然后调用该函数,但使用document.querySelectorAll
的结果作为this
对象,而不是实际数组。
document.querySelectorAll('a')
从一个 NodeList
转换为普通数组?[].slice.call(document.querySelectorAll('a'), 0)
让我们先拆开它,
[] // Array object
.slice // Accessing the function 'slice' present in the prototype of Array
.call // Accessing the function 'call' present in the prototype of function object(slice)
(document.querySelectorAll('a'),0)
// 'call' can have arguments like, (thisArg, arg1,arg2...n).
// So here we are passing the 'thisArg' as an array like object,
// that is a 'nodeList'. It will be served as 'this' object inside of slice function.
// And finally setting 'start' argument of slice as '0' and leaving the 'end'
// argument as 'undefined'
步骤1:执行call
函数
thisArg
之外,在call
内,其余的参数将被附加到参数列表中。slice
将通过将其this
值绑定为thisArg
(来自document.querySelector
的类似数组对象)并使用参数列表来调用。即]包含0
的参数start
步骤2:在call
内部调用的slice
函数的执行
start
will be assigned to a variable s
as 0
end
is undefined
, this.length
will be stored in e
a
After making the above settings the following iteration will be happened
while(s < e) {
a.push(this[s]);
s++;
}
a
will be returned as the result.[].slice.call(document.querySelectorAll('.slide'));
querySelectorAll()方法返回文档中与指定选择器匹配的所有元素。
call()方法使用给定的this值和逐个提供的参数调用函数。
slice()方法将选定的元素作为新数组对象返回。
因此,这行代码返回一个由[object HTMLDivElement]组成的数组。这里有六个class名为"slide"的div,所以数组长度将会是6。
var arraylist = [].slice.call(document.querySelectorAll('.slide'));
console.log(arraylist);
<div class="slideshow">
<div class="slide">
first slider1
</div>
<div class="slide">
first slider2
</div>
<div class="slide">
first slider3
</div>
<div class="slide">
first slider4
</div>
<div class="slide">
first slider5
</div>
<div class="slide">
first slider6
</div>
</div>
从ES6开始,您可以使用 Array.from(element.children) 或 Array.from({length: 5}) 来简单地创建数组。
在2020年代,我们使用
[...document.querySelectorAll('.slide')]
如果你想使用 map 或 filter,但不再需要使用 forEach,那么这是非常有用的,因为现在 forEach 可以在从 document.querySelectorAll('.slide')
返回的集合上工作。
这也许会有所帮助。
slice()方法将从数组的start到end(不包括end)选择的一部分浅拷贝到一个新的数组对象中。原始数组不会被修改。 了解更多:Reference/Global_Objects/Array/slice
call()允许将属于一个对象的函数/方法分配并调用另一个对象。
call()方法使用给定的this值和逐个提供的参数调用函数。 call()为函数/方法提供了一个新的this值。使用call(),您可以编写一次方法,然后在另一个对象中继承它,而无需为新对象重新编写该方法。
查看更多: 参考/全局对象/函数/call
Array.prototype.slice.call(document.querySelectorAll('a'));
是你编写的代码片段的正确书写方式。 - vdegenneArray.from
。因此,例如以下代码会达到相同的效果:Array.from(document.querySelectorAll('a'))。 - rugk