晚上看张鑫旭老师的一篇文章,发现[].slice.call()
这样的用法,很感兴趣,因为昨天刚写完一篇关于call方法的博客《一文读懂js中的call和apply》(以下简称“《call》”),想一探究竟,也正好加深对call的理解。
基础:
- slice()方法可以从已有的数组中返回选定的元素,语法:
array.slice(start, end)
,截取array中第start位到第end位之间的部分,范围:[start, end); - slice()的参数可以省略,省略时默认从0开始,一直到最后一位,也就是返回全部;
- call和apply的作用都是在特定作用域中调用函数,例如:
程序员.编程.call(外卖员)
就是在外卖员作用域中调用程序员的编程方法,即外卖员编程。
探索:
张老师[].slice.call(eleRadios)
这么写是想让eleRadios调用数组的原生方法slice()从而转换成数组格式,那么eleRadios本身不是数组吗?非得绕这么一大圈?下面贴出他的部分代码(完整版点击这里):
// 已删除部分无关代码
<input type="radio" value="default" checked>
<input type="radio" value="red">
<input type="radio" value="green">
var eleRadios = document.querySelectorAll('input[type="radio"]');
[].slice.call(eleRadios).forEach(function (radio) {
radio.addEventListener('click', function () {
// 略
});
});
通过document.querySelectorAll获取页面上所有type等于“radio”的input的节点集合eleRadios
,接着对[].slice.call(eleRadios)
进行forEach遍历,给其中每个子元素添加click点击事件。为什么不能直接调用forEach方法——就像这样eleRadios.forEach(...)
?看来eleRadios真不是数组?于是我在页面上的调试工具console中测试了一下,发现猜想是对的:
通过打印,得知eleRadios
是NodeList
类型,为了再次验证它与数组的关系,我还使用instanceof
的方式进行检测,结果一目了然:不是数组。
如果你在chrome等一些较新的浏览器上测试,会发现
感谢@lidysun的评论NodeList
类型是可以调用forEach()
的,但是这一特性并不稳定,在低版本浏览器上NodeList
并不支持forEach()
,所以,张鑫旭老师这样写应该是为了解决兼容问题。在实际开发中,我们最好使用[].slice.call()
将其转换成数组类型再调用数组的一些方法,这样比较稳妥。
原理:
现在就清楚了,为了能遍历这个NodeList
类型的eleRadios
,就使用call
方法啦:在eleRadios
这个作用域中调用数组的slice
方法,以转化成数组类型,然后调用forEach
方法实现遍历。
因为[]
是Array的实例,所以也可以写成[].slice.call()
。
2019年12月25日圣诞节补充
类数组转数组的ES6写法:
const arr = Array.from(eleRadios)
const arr = [...eleRadios]
4 条评论
wfsdaj · 2020年1月5日 上午12:14
你好,我也看了这篇文章。有个问题请教,这样切换后,一刷新就回到默认皮肤了啊?这个有什么用吗?
大海 · 2020年1月6日 上午9:34
是想解决“刷新恢复默认皮肤”的问题吗?——可以使用localStorage或者数据库存储用户的皮肤(或其他习惯),每次进入页面前先去查询这些习惯,再根据习惯渲染页面。
还是问[].slice.call()对这个问题有什么用?——没有,这个只是把类数组转换成数组格式,不用它用别的方法也可以实现的,跟业务无关。
lidysun · 2020年3月4日 上午10:01
在本页控制台运行:var div = document.querySelectorAll(‘div’) 得到NodeList集没错;
typeof div (‘object’);
div instanceof Array (false);
不用[].slice.call(div)转为数组,也可以直接 div.forEach(function(item){console.log(item)})
正常打印。
NodeList 本身就拥有forEach方法。
一文读懂js中的call和apply – 前端开发,JQUERY特效,全栈开发,vue开发 · 2020年5月28日 下午4:35
[…] call和apply在开发中的使用场景见《理解Array.prototype.slice.call()》。 […]