关于Array.prototype.slice.call()的问题

HTML代码:

<ol id="test-list">
    <li class="lang">Scheme</li>
    <li class="lang">JavaScript</li>
    <li class="lang">Python</li>
    <li class="lang">Ruby</li>
    <li class="lang">Haskell</li>
</ol>

控制台:

var list = document.getElementById('test-list')
var slist = list.children;
slist.sort(function(a, b){
   return a.innerHTML > b.innerHTML ? 1 : -1 ;
});

这里报错:Uncaught TypeError: slist.sort is not a function at <anonymous>:1:7
typeof slist测试返回是"objiect"
然后控制台输入:

slist=Array.prototype.slice.call(slist);
typeof slist;

还是返回"objiect",
但是这时控制台输入:

slist.sort(function(a, b){
   return a.innerHTML > b.innerHTML ? 1 : -1 ;
});

运行正常,没有报错.排序结果也是对的,

slist.forEach(function(el){
 list.appendChild(el);
})

运行后

<ol id="test-list">
<li class="lang">Scheme</li>
<li class="lang">JavaScript</li>
<li class="lang">Python</li>
<li class="lang">Ruby</li>
<li class="lang">Haskell</li>
</ol>

我想问一下slist=Array.prototype.slice.call(slist);这一步起到了什么作用,为什么不能直接调用sort();;进行排序?

阅读 3.4k
3 个回答

因为 Array 类型的值和 NodeList 的值 typeof 之后都是 object

typeof [] // object

你应该分别试 Object.prototype.toString.call(slist) 就会有差别。

前者应该是 [object NodeList],后者是 [object Array]

而你调用的 sort 方法存在于 Array.prototype 而不在 NodeList.prototype ,所以前者报错而后面的可以运行

slist=Array.prototype.slice.call(slist)在这里是把一个类数组对象(nodeList)转换成数组,这样就可以用数组的方法了

可以参考这篇文章,Array.prototype.slice.call(arguments),我觉得解释的不错。

其实就是用于把类数组对象转换成了数组,使用数组的一系列方法。
类数组转成数组主要有:Array.from(),[].slice.call()(Array.prototype.slice.call()),扩展运算符,也能将某些数据结构转成数组。

// arguments
function foo() {
 var args = [...arguments];
}
// NodeList对象
[...document.querySelectorAll('div')]
// Set // 区分NaN
[...new Set([1,2,3,'1',NaN,NaN])]
// [1, 2, 3, "1", NaN]
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题