js 字典与Map对象

时间:2024-10-01 20:17:32

 字典 是一种以键-值对形式存储数据的数据结构,像电话簿里面的电话和号码一样,本文字典的的基础类为Array.

字典实现:

  1. function Dictionary() {
  2. this.datastore = [];
  3. this.add = add;
  4. this.find = find;
  5. this.remove = remove;
  6. this.showAll = showAll;
  7. this.count = count;
  8. this.clear = clear;
  9. this.kSort = kSort;
  10. this.vSort = vSort
  11. }
  12. //添加
  13. function add(key,value) {
  14. this.datastore[key] = value;
  15. }
  16. //查找
  17. function find(key) {
  18. return this.datastore[key];
  19. }
  20. //删除
  21. function remove(key) {
  22. delete this.datastore[key];
  23. }
  24. //显示所有键值对
  25. function showAll() {
  26. for (var key in this.datastore) {
  27. console.log(key + ':' + this.datastore[key]);
  28. }
  29. }
  30. //计数
  31. function count() {
  32. var n = 0;
  33. for (var key in Object.keys(this.datastore)) {
  34. n++;
  35. }
  36. return n;
  37. }
  38. //清空字典
  39. function clear() {
  40. for (var key in this.datastore) {
  41. delete this.datastore[key];
  42. }
  43. }
  44. // 按键(key)排序,升序
  45. function kSort(){
  46. var dic = this.datastore;
  47. var res = Object.keys(dic).sort();
  48. for(var key in res ){
  49. console.log(res[key] + " : " + dic[res[key]]);
  50. }
  51. }
  52. // 按键(key)排序,降序
  53. function vSort(){
  54. var dic = this.datastore;
  55. var res = Object.keys(dic).sort(function(a,b){
  56. return dic[a]-dic[b];
  57. });
  58. for(var key in res ){
  59. console.log(res[key] + " : " + dic[res[key]]);
  60. }
  61. }
  62. var pbook = new Dictionary();
  63. //添加键值对
  64. pbook.add("Mike","123");
  65. pbook.add("David", "345");
  66. pbook.add("Cynthia", "456");
  67. pbook.add("Cyntddhia", "456");
  68. //显示所有数据
  69. pbook.showAll();
  70. //显示数量
  71. pbook.count();
  72. //排序
  73. pbook.vSort()
'
运行

Map 结构的实例有以下属性和操作方法

(1)size 属性

size属性返回 Map 结构的成员总数。

  1. const map = new Map();
  2. map.set('foo', true);
  3. map.set('bar', false);
  4. map.size // 2
'
运行

(2)set(key, value)

set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。

  1. const m = new Map();
  2. m.set('edition', 6) // 键是字符串
  3. m.set(262, 'standard') // 键是数值
  4. m.set(undefined, 'nah') // 键是 undefined
'
运行

set方法返回的是当前的Map对象,因此可以采用链式写法。

  1. let map = new Map()
  2. .set(1, 'a')
  3. .set(2, 'b')
  4. .set(3, 'c');
'
运行

(3)get(key)

get方法读取key对应的键值,如果找不到key,返回undefined

  1. const m = new Map();
  2. const hello = function() {console.log('hello');};
  3. m.set(hello, 'Hello ES6!') // 键是函数
  4. m.get(hello) // Hello ES6!
'
运行

(4)has(key)

has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。

  1. const m = new Map();
  2. m.set('edition', 6);
  3. m.set(262, 'standard');
  4. m.set(undefined, 'nah');
  5. m.has('edition') // true
  6. m.has('years') // false
  7. m.has(262) // true
  8. m.has(undefined) // true
'
运行

(5)delete(key)

delete方法删除某个键,返回true。如果删除失败,返回false

  1. const m = new Map();
  2. m.set(undefined, 'nah');
  3. m.has(undefined) // true
  4. m.delete(undefined)
  5. m.has(undefined) // false
'
运行

(6)clear()

clear方法清除所有成员,没有返回值。

  1. let map = new Map();
  2. map.set('foo', true);
  3. map.set('bar', false);
  4. map.size // 2
  5. map.clear()
  6. map.size // 0
'
运行

遍历方法

Map 结构原生提供三个遍历器生成函数和一个遍历方法。

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
  • forEach():遍历 Map 的所有成员。

需要特别注意的是,Map 的遍历顺序就是插入顺序。

  1. const map = new Map([
  2. ['F', 'no'],
  3. ['T', 'yes'],
  4. ]);
  5. for (let key of map.keys()) {
  6. console.log(key);
  7. }
  8. // "F"
  9. // "T"
  10. for (let value of map.values()) {
  11. console.log(value);
  12. }
  13. // "no"
  14. // "yes"
  15. for (let item of map.entries()) {
  16. console.log(item[0], item[1]);
  17. }
  18. // "F" "no"
  19. // "T" "yes"
  20. // 或者
  21. for (let [key, value] of map.entries()) {
  22. console.log(key, value);
  23. }
  24. // "F" "no"
  25. // "T" "yes"
  26. // 等同于使用()
  27. for (let [key, value] of map) {
  28. console.log(key, value);
  29. }
  30. // "F" "no"
  31. // "T" "yes"
'
运行

上面代码最后的那个例子,表示 Map 结构的默认遍历器接口(属性),就是entries方法。

  1. map[Symbol.iterator] === map.entries
  2. // true

Map 结构转为数组结构,比较快速的方法是使用扩展运算符(...)。

  1. const map = new Map([
  2. [1, 'one'],
  3. [2, 'two'],
  4. [3, 'three'],
  5. ]);
  6. [...map.keys()]
  7. // [1, 2, 3]
  8. [...map.values()]
  9. // ['one', 'two', 'three']
  10. [...map.entries()]
  11. // [[1,'one'], [2, 'two'], [3, 'three']]
  12. [...map]
  13. // [[1,'one'], [2, 'two'], [3, 'three']]

结合数组的map方法、filter方法,可以实现 Map 的遍历和过滤(Map 本身没有mapfilter方法)。

  1. const map0 = new Map()
  2. .set(1, 'a')
  3. .set(2, 'b')
  4. .set(3, 'c');
  5. const map1 = new Map(
  6. [...map0].filter(([k, v]) => k < 3)
  7. );
  8. // 产生 Map 结构 {1 => 'a', 2 => 'b'}
  9. const map2 = new Map(
  10. [...map0].map(([k, v]) => [k * 2, '_' + v])
  11. );
  12. // 产生 Map 结构 {2 => '_a', 4 => '_b', 6 => '_c'}
'
运行

此外,Map 还有一个forEach方法,与数组的forEach方法类似,也可以实现遍历。

  1. map.forEach(function(value, key, map) {
  2. console.log("Key: %s, Value: %s", key, value);
  3. });

forEach方法还可以接受第二个参数,用来绑定this

  1. const reporter = {
  2. report: function(key, value) {
  3. console.log("Key: %s, Value: %s", key, value);
  4. }
  5. };
  6. map.forEach(function(value, key, map) {
  7. this.report(key, value);
  8. }, reporter);

上面代码中,forEach方法的回调函数的this,就指向reporter

与其他数据结构的互相转换

(1)Map 转为数组

前面已经提过,Map 转为数组最方便的方法,就是使用扩展运算符(...)。

  1. const myMap = new Map()
  2. .set(true, 7)
  3. .set({foo: 3}, ['abc']);
  4. [...myMap]
  5. // [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]
'
运行

(2)数组 转为 Map

将数组传入 Map 构造函数,就可以转为 Map。

  1. new Map([
  2. [true, 7],
  3. [{foo: 3}, ['abc']]
  4. ])
  5. // Map {
  6. // true => 7,
  7. // Object {foo: 3} => ['abc']
  8. // }
'
运行

(3)Map 转为对象

如果所有 Map 的键都是字符串,它可以无损地转为对象。

  1. function strMapToObj(strMap) {
  2. let obj = Object.create(null);
  3. for (let [k,v] of strMap) {
  4. obj[k] = v;
  5. }
  6. return obj;
  7. }
  8. const myMap = new Map()
  9. .set('yes', true)
  10. .set('no', false);
  11. strMapToObj(myMap)
  12. // { yes: true, no: false }
'
运行

如果有非字符串的键名,那么这个键名会被转成字符串,再作为对象的键名。

(4)对象转为 Map

  1. function objToStrMap(obj) {
  2. let strMap = new Map();
  3. for (let k of Object.keys(obj)) {
  4. strMap.set(k, obj[k]);
  5. }
  6. return strMap;
  7. }
  8. objToStrMap({yes: true, no: false})
  9. // Map {"yes" => true, "no" => false}
'
运行

(5)Map 转为 JSON

Map 转为 JSON 要区分两种情况。一种情况是,Map 的键名都是字符串,这时可以选择转为对象 JSON。

  1. function strMapToJson(strMap) {
  2. return JSON.stringify(strMapToObj(strMap));
  3. }
  4. let myMap = new Map().set('yes', true).set('no', false);
  5. strMapToJson(myMap)
  6. // '{"yes":true,"no":false}'

另一种情况是,Map 的键名有非字符串,这时可以选择转为数组 JSON。

  1. function mapToArrayJson(map) {
  2. return JSON.stringify([...map]);
  3. }
  4. let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
  5. mapToArrayJson(myMap)
  6. // '[[true,7],[{"foo":3},["abc"]]]'
'
运行

(6)JSON 转为 Map

JSON 转为 Map,正常情况下,所有键名都是字符串。

  1. function jsonToStrMap(jsonStr) {
  2. return objToStrMap(JSON.parse(jsonStr));
  3. }
  4. jsonToStrMap('{"yes": true, "no": false}')
  5. // Map {'yes' => true, 'no' => false}

但是,有一种特殊情况,整个 JSON 就是一个数组,且每个数组成员本身,又是一个有两个成员的数组。这时,它可以一一对应地转为 Map。这往往是 Map 转为数组 JSON 的逆操作。

  1. function jsonToMap(jsonStr) {
  2. return new Map(JSON.parse(jsonStr));
  3. }
  4. jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
  5. // Map {true => 7, Object {foo: 3} => ['abc']}
'
运行

相关文章