JavaScript中 .slice.call的解释
我偶然发现了将DOM NodeList转换为常规数组的简洁捷径,但是我必须承认,我并不完全理解它是如何工作的:
[].slice.call(document.querySelectorAll('a'), 0)
所以它开始于一个空的数组[]
,然后slice
被用来将call
的结果转换为一个新的数组呀。
我不明白的是call
。 如何将document.querySelectorAll('a')
从NodeList转换为常规数组?
这里发生的是你使用call slice()
调用slice()
,就好像它是NodeList
一个函数一样。 在这种情况下, slice()
会创build一个空数组,然后遍历它所运行的对象(最初是一个数组,现在是一个NodeList
),并将该对象的元素附加到它创build的空数组中,最终返回。 这里有一篇文章 。
编辑:
所以它开始于一个空的数组[],然后切片被用来将调用的结果转换为一个新的数组呀。
那是不对的。 [].slice
返回一个函数对象。 一个函数对象有一个函数call()
,它调用函数将call()
的第一个参数赋值给this
; 换句话说,使函数认为它是从参数(由document.querySelectorAll('a')
返回的NodeList
)而不是从数组中调用的。
在JavaScript中,对象的方法可以在运行时绑定到另一个对象。 总之,javascript允许一个对象“借用”另一个对象的方法:
object1 = { name:'frank', greet:function(){ alert('hello '+this.name) } }; object2 = { name:'andy' }; // Note that object2 has no greet method. // But we may "borrow" from object1: object1.greet.call(object2);
函数对象的call
和apply
方法(在JavaScript函数中也是对象)允许你这样做。 所以在你的代码中你可以说NodeList借用了一个数组的slice方法。 什么是转换是事实上切片返回另一个数组,因为它的结果。
它从Array
检索slice
函数。 然后它调用该函数,但将document.querySelectorAll
的结果用作this
对象而不是实际的数组。
这是一种将类似数组的对象转换为真实数组的技术。
其中一些对象包括:
- 在函数中的
arguments
- NodeList (记住,它们的内容可以在获取后更改!所以将它们转换为数组是冻结它们的一种方法)
- jQuery集合,又名jQuery对象(一些文档: API , types , 学习 )
这有很多用途,例如对象是通过引用传递的,而数组是通过值传递的。
另外,注意第一个参数0
可以省略, 这里详细说明 。
为了完整起见,还有jQuery.makeArray() 。
如何将
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
function
- 除了
thisArg
,其他的参数将被附加到参数列表中。 - 现在函数
slice
将通过绑定其this
值为thisArg
(类似于对象的数组来自document.querySelector
)和参数列表来调用。 即]包含0
参数start
步骤:2调用内部call
slice
函数的执行
-
start
将被赋值为一个variabless
为0
- 由于
end
是undefined
,this.length
将被存储在e
- 一个空数组将被存储在一个variables
a
-
完成上述设置后,将会发生以下迭代
while(s < e) { a.push(this[s]); s++; }
- 填满的数组
a
将作为结果返回。
PS为了更好的理解我们的场景,我们的上下文所需要的一些步骤已经被原始的调用和切片algorithm所忽略。
[].slice.call(document.querySelectorAll('.slide')); 1. The querySelectorAll() method returns all elements in the document that matches a specified selector(s). 2. The call() method calls a function with a given this value and arguments provided individually. 3. The slice() method returns the selected elements in an array, as a new array object. so this line return the array of [object HTMLDivElement]. Here is the six div with classname "slide" so array length will be 6. <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> <script type="text/javascript"> var arraylist = [].slice.call(document.querySelectorAll('.slide')); alert(arraylist); </script>
从ES6:只需使用Array.from(element.children)或Array.from({length:5})创build数组