如何检查Backbone集合是否已包含同idAttribute值的模型?
这个问题我之前也碰到过!核心问题出在你用findWhere时的对象键写法不对,而且其实Backbone本身就有更简便的方法来处理这种基于idAttribute的存在性判断,不用自己手动绕弯路~
先说说你现有代码的问题:
你写的myCollection.findWhere({ idAttribute : id })里,对象字面量的键是字符串"idAttribute",而不是你变量idAttribute的值(比如你自定义的"uuid"或者其他),所以它在找所有模型里idAttribute这个属性等于id的模型,而不是你实际要匹配的那个自定义ID属性,这就是为什么返回undefined。
下面给你几种靠谱的解决方案:
1. 最简便:用Backbone集合的get方法
Backbone.Collection的get方法会自动识别模型的idAttribute,不管你设置的是默认的"id"还是自定义的属性名,直接传入ID值就能查找:
const idAttribute = myCollection.model.prototype.idAttribute; const id = itemToInsert.get(idAttribute); const exists = !!myCollection.get(id); // 存在返回true,不存在返回false
这个方法是Backbone官方推荐的,内部已经帮你处理了idAttribute的映射,最省心。
2. 修正findWhere的写法
如果你还是想用findWhere,需要用ES6的计算属性名,把变量idAttribute的值作为对象的键:
const idAttribute = myCollection.model.prototype.idAttribute; const id = itemToInsert.get(idAttribute); const existingModel = myCollection.findWhere({ [idAttribute]: id }); const exists = !!existingModel;
这里的[idAttribute]会把变量的值解析成属性名,比如如果idAttribute是"userId",就会生成{ userId: id }的查询条件,这样就能正确匹配了。
3. 手动遍历:用Underscore的some方法
如果你想自己实现遍历判断,Backbone集合集成了Underscore的方法,直接用some就行(和你想的_.any是同一个方法,Underscore里_.any是_.some的别名):
const idAttribute = myCollection.model.prototype.idAttribute; const targetId = itemToInsert.get(idAttribute); const exists = myCollection.some(item => item.get(idAttribute) === targetId);
这个方法会遍历集合里的每个模型,只要有一个模型的idAttribute值和目标值相等,就返回true。
另外补充一下:你说的myCollection.contains(myNewModel)返回false是正常的,因为contains是严格比较对象实例——只有当你传入的模型是集合里已经存在的同一个对象引用时才会返回true,哪怕两个模型的所有属性都一样,只要是不同实例,contains就会返回false,所以确实不能用它来判断同ID的模型是否存在。
内容的提问来源于stack exchange,提问作者TTT

