hjin-me / blog

This is my blog
http://huangj.in
Other
9 stars 2 forks source link

不鸡肋的 Map #6

Open hjin-me opened 8 years ago

hjin-me commented 8 years ago
let m = new Map()
let key = {a:1}
m.set(key, true)
m.has(key) // true
m.has({a:1}) // false

虽然 Map 可以用任意类型做 Key 了。 但是 Key 的相等判断用的是 ===,导致用 Object 做 key 基本是废的。见 ecma262 7.2.10 SameValueZero(x, y)

要你何用!

---------------- 更新 ----------------------

思路被局限了,key 的范围被自己局限在可以通过JSON.parse获得的对象上。

更合理的 Map 的使用方式是管理那些实例化的对象,理由如下:

  1. 实例化的对象必然会在某个地方被引用,故不需要一个额外的管理 Key 的空间
  2. 库类可以通过 Map 建立实例和其他数据的映射关系,从实例对象剥离部分属性或者行程私有属性。

举个业务例子,例如给页面的 DOM 元素绑定 click 事件

let clickMap = new Map()
let div = document.querySelector('div')
click(div, function() {
  // listerner
})

trigger(div)

function click(el, fn) {
  let listeners = clickMap.get(el)
  if(!listeners) {
    listeners = []
  }
  listeners.push(fn)
  clickMap.set(el, listeners)
}

function trigger(el) {
  let listeners = clickMap.get(el)
  if(!listeners) {
    listeners = []
  }
  listeners.forEach(fn => {
    fn()
  })
}
iwillwen commented 8 years ago

有用,不過是特定場景。 好比在 MinDB 中,需要實現 ZSET 的數據結構,就需要做雙向映射表,但是 JS 沒有類似的結構,在 ES5 時代更沒有真正的高可用 Hash 算法或者 API。而 mindb 的做法便是使用 Object + Array 來模擬雙向映射。

反觀 ES2015 的 Map,因為可以直接用 Object 作為 Key,所以就可以很好解決雙向映射的需求了。

hjin-me commented 8 years ago

@iwillwen 我自己没有理解你的业务场景里关于使用 Object 做 Key 时对我的疑问的解答。

我认为当 Map 的 Key 是 Object 时,我还需要一个额外的数据结构(M)来保存原来的 key,而引入这个额外的数据结构后,Map 就没什么意义了。例如如下代码

let keyArr = []  // 保存 Key 的数组
ley k = {x:1}
let m = new Map()
m.set(k, 'alpha')
keyArr.push(k)

let x = {x:1}
let k2
for(var o of keyArr) {
  if(equals(x, o) {
    k2 = o
  }
}
m.has(k2) // true

function equals(obj1, obj2) {
 // 判断两个 obj 里面的值是否相同的函数,类似 angular.equal
}

如果我不保存 keyArr,我就只能对 Map 进行 for of,然后一个一个用 equals 方法检查 Key 是否匹配。

无论哪种方法,都可以用 ES5 重写并且不会增加额外的代码量。那 Map 有什么意义?