232

我偶然发现了这个将 DOM NodeList 转换为常规数组的简洁快捷方式,但我必须承认,我并不完全理解它是如何工作的:

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

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

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

4

9 回答 9

174

这里发生的事情是你调用slice()它就好像它是NodeListusing的一个函数call()。在slice()这种情况下所做的是创建一个空数组,然后遍历它正在运行的对象(最初是一个数组,现在是 a NodeList)并继续将该对象的元素附加到它创建的空数组中,最终返回。这是一篇关于此的文章。

编辑:

所以它从一个空数组[]开始,然后切片用于将调用结果转换为一个新数组是吗?

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

于 2010-01-24T03:00:46.730 回答
147

在 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()返回另一个数组作为结果,它将成为您可以使用的“转换后的”数组。

于 2010-01-24T04:01:11.370 回答
32

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

于 2010-01-24T03:01:30.940 回答
21

这是一种将类数组对象转换为真实数组的技术。

其中一些对象包括:

  • arguments在函数中
  • NodeList(记住它们的内容在获取后可能会改变!所以将它们转换为数组是一种冻结它们的方法)
  • jQuery 集合,又名 jQuery 对象(一些文档:APItypelearn

这有很多用途,例如对象通过引用传递,而数组通过值传递。

另外,请注意第一个参数0可以省略,这里有详尽的解释

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

于 2015-04-09T04:42:36.890 回答
18

这如何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'

Step: 1call函数的执行

  • 在 内部call,除了 之外thisArg,其余参数将附加到参数列表中。
  • 现在该函数slice将通过将其this值绑定为 thisArg(array like object came from document.querySelector) 和参数列表来调用。ie] 参数start包含0

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

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

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

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

于 2016-03-15T17:45:11.217 回答
7
[].slice.call(document.querySelectorAll('.slide'));
  1. querySelectorAll() 方法返回文档中与指定选择器匹配的所有元素。

  2. call() 方法使用给定的 this 值和单独提供的参数调用函数。

  3. slice() 方法将数组中的选定元素作为新的数组对象返回。

所以这一行返回 [object HTMLDivElement] 的数组。这是类名为“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>

于 2017-02-17T10:21:02.737 回答
7

来自 ES6:只需使用Array.from(element.children)Array.from({length: 5})创建数组

于 2017-10-30T21:58:42.623 回答
0

这也可能有帮助。

切片法

描述:

slice 不会改变原始数组。它从原始数组返回元素的浅表副本。原始数组的元素被复制到返回的数组中。

slice() 方法将数组的一部分的浅表副本返回到从开始到结束(不包括结束)选择的新数组对象中,其中开始和结束表示该数组中项目的索引。原始数组不会被修改。查看更多:参考/Global_Objects/Array/slice

调用方法

描述:

call() 允许为不同的对象分配和调用属于一个对象的函数/方法。

call() 方法使用给定的 this 值和单独提供的参数调用函数。call() 为函数/方法提供了 this 的新值。使用 call(),您可以编写一次方法,然后在另一个对象中继承它,而无需为新对象重写方法。

查看更多:参考/Global_Objects/Function/call

于 2020-08-27T07:31:51.660 回答
0

在 2020 年代,我们使用

[...document.querySelectorAll('.slide')]

当您想使用 map 或 filter 但不再需要使用 forEach 时,它很有用,因为 forEach 现在适用于从返回的集合document.querySelectorAll('.slide')

于 2022-02-15T07:47:28.747 回答