JS展开语法(…)与querySelectorAll

偶尔会写几个 userscripts 来改善浏览某些网站时的体验,一般是修改排序或者移除不需要的元素。通常在移除元素时,都会使用 document.querySelectorAll() 这种方式选中元素,然后进行移除操作。

Document.querySelectorAll() 方法得到的结果,可以进行 forEach 循环,这也是我们方便移除某些元素的方式。所以,很容易将其返回值理解为一个数组。其实并不是这样。Document.querySelectorAll 返回的是一个元素列表(NodeList),不是普通列表 。虽然 NodeList 支持 forEach 遍历或者 lenght 属性,但它并非与 Array 一致,详见 NodeList。比如说:

let A = document.querySelector('.a');
let B = document.querySelector('.b');
A.forEach(function(a){
    B.push(a);
});

以上代码,在 B.push(a) 的时候就会报错,因为 B 并不是一个数组,而是 NodeList,NodeList 没有 push 方法。所以,如果我们有多个广告元素,想要合并成一个,再统一移除,就需要有一个额外的广告元素列表,比如将以上代码改为:

let ads = [];
let ad1s = document.querySelector('.ad1');
ad1s.forEach(function(ad1){
    ads.push(ad1);
});
let ad2s = document.querySelector('.ad2');
ad2s.forEach(function(ad2){
    ads.push(ads);
});

以上代码看上去就比较臃肿,如果同类元素更多的话,就会有更多个重复的 forEach 和 push。JS 有一种语法,叫做展开语法(Spread syntax),其表达式为 …iterableObj,比如数组:

let a = [1, 2, 3];
let b = [4, 5, 6];
a.push(...b)
// 此时 a 为 [1, 2, 3, 4, 5, 6]

这种展开语法,会给我们带来很多便利,比如在合并数组时,我们不需要再用 forEach 去遍历就可以直接追加,简洁了很多。而展开语法并不是只能在数组上使用,在任何可遍历的对象上都可以使用,NodeList 就是一种可遍历的对象。那么我们可以编写以下代码,实现合并 NodeList。

let ads = [];
let ad1s = document.querySelector('.ad1');
let ad2s = document.querySelector('.ad2');
ads.push(...ad1s, ...ad2s)

由于 JS 没有提供移除当前元素的 API,所以我们需要先找到其父元素再移除父元素下面对应的子元素,参见 Node.removeChild()

if (ads){
    ads.forEach(function(ad){
        ad.parentNode.removeChild(ad);
    });
};

最后提一下,在 MDN(Mozilla Developer Network) 上看文档比在国内的网站上容易太多了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注