javascript 中 [].slice.call 的解释?

Posted

技术标签:

【中文标题】javascript 中 [].slice.call 的解释?【英文标题】:Explanation of [].slice.call in javascript? 【发布时间】:2011-01-08 16:52:29 【问题描述】:

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

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

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

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

【问题讨论】:

Array.prototype.slice.call(document.querySelectorAll('a')); 是编写您编写的代码块的正确方法。 顺便说一句,现代(直观易懂)的 ES6 方法是 Array.from。所以例如这会做同样的事情: Array.from(document.querySelectorAll('a')); 这能回答你的问题吗? how does Array.prototype.slice.call() work? 【参考方案1】:

这里发生的情况是,您调用slice(),就好像它是使用call()NodeList 的函数一样。 slice() 在这种情况下所做的是创建一个空数组,然后遍历它正在运行的对象(最初是一个数组,现在是一个 NodeList)并继续将该对象的元素附加到它创建的空数组中,即最终回来了。这是article on this。

编辑:

所以它以一个空数组[]开头,然后使用slice 将调用结果转换为新数组好吗?

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

【讨论】:

这里还要注意,虽然这在语义上等同于说Array.prototype.slice.call(...),但它实际上实例化一个数组对象([])只是为了访问它的原型切片方法。那是浪费的实例化。说Array.prototype.slice.call(...) 更简洁,尽管如果你在数数的话,你会在你的 JS 中添加几个字符...... 请注意,这仅适用于 IE 8 及更低版本的 Array 对象,因此您将无法克隆 NodeLists @quixoto [] 更可靠,因为Array 可以被其他东西覆盖。如果您需要重用Array#slice,最好将其缓存起来。 如果其他人正在寻找在 IE8 中执行此操作的方法,请查看此问题 ***.com/questions/3199588/… 我实际上在backbone.js源代码中看到了这种模式:var array = []; var push = array.push; var slice = array.slice; var splice = array.splice;他这样做是为了@MathiasBynens提到的安全问题吗?【参考方案2】:

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

【讨论】:

Bang on ? javascript 对象函数的抽象概念解释。现在,您可以将其应用于Array.prototype aka [].prototypecall 函数。【参考方案3】:

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

【讨论】:

【参考方案4】:

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

其中一些对象包括:

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

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

另外,请注意第一个参数 0 可以省略,thorough explanation here。

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

【讨论】:

【参考方案5】:

如何将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函数

call 内,除了thisArg,其余的参数 将被附加到参数列表中。 现在函数slice 将通过将其this 值绑定为来调用 thisArg(类似数组的对象来自document.querySelector)和参数列表。即] 参数start 包含0

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

start 将分配给变量 s 作为 0 由于endundefinedthis.length 将存储在e 一个空数组将被存储在一个变量a

进行上述设置后,将发生以下迭代

while(s < e) 
  a.push(this[s]);
  s++;

填满的数组a将作为结果返回。

P.S 为了更好地理解我们的场景,call 和 slice 的原始算法已经忽略了我们的上下文所必需的一些步骤。

【讨论】:

非常好的一步一步的解释。惊人的!谢谢你:) 很好的解释。【参考方案6】:
[].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>

【讨论】:

【参考方案7】:

来自 ES6:只需使用 Array.from(element.children)Array.from(length: 5)

制作数组

【讨论】:

【参考方案8】:

这也可能有帮助。

切片方法

说明:

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

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

调用方法

说明:

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

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

查看更多:Reference/Global_Objects/Function/call

【讨论】:

以上是关于javascript 中 [].slice.call 的解释?的主要内容,如果未能解决你的问题,请参考以下文章

将一个类数组对象转化为数组的几种方法

ES6标准学习: 4数组的扩展

数组对象新增方法Array.from()Array.of()

javascript中直接写php代码的方法

javascript中valueOf()方法的用法?

javascript 从一个数组中 删除 一个数组