JavaScript中indexOf始终返回-1,数组重复添加问题求助
问题分析与修复方案
你的代码里明明做了indexOf判断,却还是重复添加元素,而且indexOf一直返回-1,这个问题我之前也遇到过,主要是Firebase数据处理和数组判断的细节没注意到,咱们一步步来理清楚:
1. 嵌套遍历导致的重复触发逻辑
你在pois.forEach里面嵌套了tags.forEach,这意味着每一个pois元素都会把所有tag节点遍历一遍。哪怕某个tag已经被加到tagsToUse里了,只要后面还有pois元素匹配到这个tag,就会再跑一次判断——这时候如果indexOf失效,自然就会重复添加。
2. indexOf返回-1的核心原因
indexOf是用**严格相等(===)**来匹配元素的,失效通常是这两种情况:
- Firebase返回的
name不是基本类型:如果你的数据库里tag下的name是个对象(不是字符串/数字),那t.child('name').val()拿到的是对象引用。哪怕两个对象内容一模一样,引用地址不同,indexOf就认不出来,返回-1。 - 值存在隐形差异:比如
name前后有空格(" 咖啡 "和"咖啡")、大小写不一样("Coffee"和"coffee"),肉眼看着相同,但indexOf会当成不同的元素。
修复后的代码
我把你的代码优化了一下,既解决了重复遍历的问题,也统一了值类型,避免indexOf失效:
var tagsToUse = []; var refTags = firebase.database().ref('/tag/'); // 先把Firebase的快照转成普通对象,不用每次遍历都操作快照 refTags.once('value', function(tagsSnapshot) { const tagMap = tagsSnapshot.val() || {}; pois.forEach(p => { // 直接用p.tag当key找对应的tag,不用嵌套遍历所有tag const matchedTag = tagMap[p.tag]; if (matchedTag) { // 强制转成字符串+去除空格,保证类型统一、值无隐形差异 const tagName = String(matchedTag.name).trim(); if (tagsToUse.indexOf(tagName) === -1) { tagsToUse.push(tagName); console.log("Added " + tagName); } else { console.log("Already exists: " + tagName); } } }); });
更高效的去重方式
其实用ES6的Set来存tag名称更省心,它天然会帮你去重,比indexOf效率还高:
const tagsSet = new Set(); var refTags = firebase.database().ref('/tag/'); refTags.once('value', function(tagsSnapshot) { const tagMap = tagsSnapshot.val() || {}; pois.forEach(p => { const matchedTag = tagMap[p.tag]; if (matchedTag) { const tagName = String(matchedTag.name).trim(); tagsSet.add(tagName); } }); // 最后把Set转成数组就行 const tagsToUse = Array.from(tagsSet); console.log(tagsToUse); });
最后记得检查一下你Firebase数据库里的name字段,确保是字符串类型,要是有多余空格也可以提前清理掉,这样就不会再出现重复添加的问题啦。
内容的提问来源于stack exchange,提问作者Usr
相关产品推荐
相关产品推荐

