JS的另一些坑
昨天要实现一个类似于筛选的功能,落实到最后,其实就是要在一个 Array
里挑出符合一定条件的元素。恰好,在前后台都有类似的需求,分别用 JavaScript 和 Ruby 两种不同的语法实现。
Ruby 常用的数组方法
在 Ruby 里,数组的方法很好用,昨天顺便总结了一下。
a = [1, 2, 3, 4, 5]
b = [3, 4, 5, 6, 7]
a - b # 从 a 中删除掉 a, b 同时存在的元素,结果是 [1, 2]
a + b # 把 a 的元素加上 b 的元素,组成一个新的数组,结果是 [1, 2, 3, 4, 5, 3, 4, 5, 6, 7]
a | b # 将 a 和 b 取并集,相当于将 a+b 再去重,也就是 (a+b).uniq,结果是 [1, 2, 3, 4, 5, 6, 7]
a & b # 将 a 和 b 取交集,取出 a 和 b 都包含的元素组成新数组,结果是 [3, 4, 5]
a.include?(1) # 判断 a 中是否存在元素 1, 结果是 true
1.in?(a) # Rails有这个语法,原生Ruby是没有的,同样是判断 a 中是否存在元素 1,结果是 true
a.reject { |aa| aa < 2 } # 将 a 中小于 2 的元素删除,结果是 [2, 3, 4, 5]
a.map { |aa| aa >=2 } # 取出 a 中大于等于 2 的元素,结果是 [2, 3, 4, 5]
JS 数组的错误用法
前台是 Javascript,数组用起来好像就没那么方便了。
a = [{id:1, title:a1}, {id:2, title: a2}, {id:3, title: a3}]
b = [2, 3]
以上是两个数组,对于数组 a 来说,它的元素是三个 hash;而数组 b 则是简单的数组。我要实现的一个功能是,从数组 a 中挑出满足 id
属于数组 b 的所有元素。以上的例子,我要实现的结果是得到一个 [{id:2, title: a2}, {id:3, title: a3}]
的新数组。
查了一下 JavaScript 的语法,用一个 filter
方法,有点类似于 Ruby 中的 map
方法,可以把满足条件的元素过滤出来。再查一下,惊喜地发现居然 Javascript 也有 in
方法,于是,我就写了这样的代码:
a.filter(function(e) { return e.id in b })
逻辑非常清晰,但是却得不到想要的结果。搞了好久,也不知道哪里出了问题。只好问同事。同事过来一看,他说,JavaScript 里用 in
这个语法吗?
当然有啊,我明明查到了,于是打开文档给他看。仔细一看,in
方法确实是有,但完全不是我认为的那个意思。
The in operator returns
true
if the specified property is in the specified object.
在 JavaScript 里,in
方法是用来判断一个对象是否具有某个属性的。看官方的例子:
// Arrays
var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
0 in trees // returns true
3 in trees // returns true
6 in trees // returns false
'bay' in trees // returns false (you must specify the
// index number, not the value at that index)
'length' in trees // returns true (length is an Array property)
Symbol.iterator in trees // returns true (arrays are iterable, works only in ES2015+)
// Predefined objects
'PI' in Math // returns true
// Custom objects
var mycar = {make: 'Honda', model: 'Accord', year: 1998};
'make' in mycar // returns true
'model' in mycar // returns true
JS 数组的正确用法
那应该用什么方法呢?我继续查了一下文档,可以用的是 includes
方法,这个方法就跟 Ruby 中的 include?
方法一致了。
a.filter(function(e) { return b.includes(e.id) })
改完之后,我发现还是不对。继续查找原因,发现在项目中,b
数组的元素竟然是 String
类型的。所以,最后正确的写法是这样的。
a = [{id:1, title:a1}, {id:2, title: a2}, {id:3, title: a3}]
b = ["2", "3"]
c = a.filter(function(e) { return b.includes(e.id.toString()) })
// 得到结果是 [{id:2, title: a2}, {id:3, title: a3}]
总结
总结一下, in
方法看起来非常直观,但是
- 原生的 Ruby 没有这个方法
- JavaSript 里有这个方法,但是并非想象中的那个意思
- Rails 中封装了
in?
的方法,用来判断某个对象是否某个数组的元素