用JavaScript解释[] .slice.call?


197

我偶然发现了这个精巧的快捷方式,用于将DOM NodeList转换为常规数组,但是我必须承认,我不完全了解它的工作方式:

[].slice.call(document.querySelectorAll('a'), 0)

因此,它以一个空数组开头[],然后slice用于将结果转换call为新数组,是吗?

我不明白的是call。它如何document.querySelectorAll('a')从NodeList转换为常规数组?


5
Array.prototype.slice.call(document.querySelectorAll('a'));是编写您编写的代码块的正确方法。
vdegenne

4
顺便说一句,现代(且直观易懂)的ES6方法是 Array.from。因此,例如这将做同样的事情:Array.from(document.querySelectorAll('a'));
rug

Answers:


158

这里发生的是,您调用slice()它就像是NodeList使用的功能call()slice()在这种情况下,要做的是创建一个空数组,然后遍历其运行的对象(最初是一个数组,现在是一个数组NodeList),并将该对象的元素附加到其创建的空数组中,最终将其返回。这是有关此文章

编辑:

因此,它以空数组[]开头,然后使用slice将调用结果转换为新数组,是吗?

那是不对的。[].slice返回一个函数对象。函数对象具有一个函数call(),该函数调用将call()to 的第一个参数赋给to 的函数this;换句话说,使函数认为它是从参数(由NodeList返回document.querySelectorAll('a'))而不是从数组中调用的。


59
还要注意,尽管这在语义上等同于说Array.prototype.slice.call(...),但实际上它实例化了一个数组对象([]),仅用于访问其原型slice方法。那是浪费的实例化。Array.prototype.slice.call(...)相反,说起来比较干净,尽管如果您要数的话,您可以在JS中添加几个字符……
Ben Zotto 2010年

请注意,这仅在IE 8及更低版本中适用于Array对象,因此您将无法克隆NodeLists
Livingston Samuel

5
@quixoto []更可靠,因为它Array可能会被其他内容覆盖。如果需要重用Array#slice,则最好将其缓存。
Mathias Bynens 2011年

2
如果其他人正在寻找一种方式,IE8要做到这一点,看看这个问题stackoverflow.com/questions/3199588/...
利亚姆Newmarch

1
我实际上看到此模式出现在var array = []; var push = array.push; var slice = array.slice; var splice = array.splice;ribs.js 源代码中: 他是否针对@MathiasBynens提到的安全性问题这样做?
owensmartin

125

在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'

函数对象的callapply方法(在JavaScript中,函数也是对象)允许您执行此操作。因此,在您的代码中,您可以说NodeList借用了数组的slice方法。.slice()返回另一个数组作为其结果,该数组将成为您可以使用的“转换后”数组。


on javascript对象功能的抽象概念说明。现在,你可以申请它call的功能Array.prototype又名[].prototype自己。
Sourabh

29

slice从中检索函数Array。然后,它调用该函数,但使用结果document.querySelectorAll作为this对象而不是实际数组。


19

它是一种将类似数组的对象转换为实际数组的技术。

其中一些对象包括:

  • arguments 在功能上
  • NodeList(请记住,它们的内容在获取后可能会更改!因此将它们转换为数组是冻结它们的一种方法)
  • jQuery集合,又名jQuery对象(一些文档:APItypelearning

这有许多目的,例如,对象是通过引用传递的,而数组是通过值传递的。

另外,请注意0这里可以省略第一个参数,并在此处进行详细说明

为了完整起见,还有jQuery.makeArray()


15

它如何document.querySelectorAll('a')从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功能

  • 在内call,除以外的thisArg其他参数将附加到参数列表中。
  • 现在,该函数slice将通过将其this值绑定为 thisArg(像来自对象的数组之类document.querySelector)并与参数列表绑定来调用。即]参数start包含0

步骤:2 slice在内部执行的函数的执行call

  • start将被分配给一个变量s作为0
  • 由于endundefinedthis.length将存储在e
  • 空数组将存储在变量中 a
  • 进行上述设置后,将发生以下迭代

    while(s < e) {
      a.push(this[s]);
      s++;
    }
  • 填充的数组a将作为结果返回。

PS为了更好地理解我们的场景,从调用切片的原始算法中忽略了一些上下文所需的步骤。


1
很好的逐步说明。太棒了!谢谢:)
kittu '17

1
很好的解释。
NaveenDA '17

7
[].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>

4

从ES6:只需使用Array.from(element.children)Array.from({length:5})制作数组

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.