何时使用Map来代替普通的JS对象


Posted in Javascript onApril 29, 2021

1. Map 接受任何类型的键

如前所述,如果对象的键不是string或symbol,JS 将隐式地将其转换为字符串。

幸运的是,map的键类型没有问题

const numbersMap = new Map();

numbersMap.set(1, 'one');
numbersMap.set(2, 'two');

[...numbersMap.keys()]; // => [1, 2]

1和2是numbersMap中的键,这些键的类型(数字)保持不变。

可以在mpa中使用任何键类型:数字、布尔值、字符串和symbol。

const booleansMap = new Map();

booleansMap.set(true, "Yep");
booleansMap.set(false, "Nope");

[...booleansMap.keys()]; // => [true, false]

booleansMap使用booleans作为键,没有问题。相反,布尔键在普通对象中不起作用。

来突破一下想象:是否将整个对象作为map的键,答案:可以的。

对象作为键

假设你需要存储一些与对象相关的数据,而不需要将这些数据附加到对象本身。使用普通对象是不可能的。

解决方法是使用对象-值元组数组:

const foo = { name: 'foo' };
const bar = { name: 'bar' };

const kindOfMap = [
  [foo, 'Foo related data'],
  [bar, 'Bar related data']
]

kindOfMap是一个数组,包含对象和关联值的对。

这种方法最大的问题是按键访问值的复杂度O(n),咱们必须遍历整个数组才能通过键获得所需的值。

function getByKey(kindOfMap, key) {
  for (const [k, v] of kindOfMap) {
    if (key === k) {
      return v;
    }
  }
  return undefined;
}

getByKey(kindOfMap, foo); // => 'Foo related data'

WeakMap(Map的一个专门版本)不需要这么麻烦就能做到上面的事情:它只接受对象作为键。

Map和Weakmap之间的主要区别是,Weakmap允许对键对象进行垃圾收集,从而防止内存泄漏。

好了,用WeakMap重构上面的代码就变得很简单了:

const foo = { name: 'foo' };
const bar = { name: 'bar' };

const mapOfObjects = new WeakMap();

mapOfObjects.set(foo, 'Foo related data');
mapOfObjects.set(bar, 'Bar related data');

mapOfObjects.get(foo); // => 'Foo related data'

与Map相反,WeakMap只接受对象作为键,并少了一些方法。

2. map 对键名没有限制

JS 中的任何对象都从原型对象继承属性,普通对象也是如此。

如果重写从原型继承的属性,则可能会破坏依赖这些原型属性的代码:

function isPlainObject(value) {
  return value.toString() === '[object Object]';
}

const actor = {
  name: 'Harrison Ford',
  toString: 'Actor: Harrison Ford'
};

// Does not work!
isPlainObject(actor); // TypeError: value.toString is not a function

在对象参与者上定义的属性toString覆盖从原型继承的toString()方法。这中断了isObject(),因为它依赖于toString()方法。

检查普通对象从原型继承的属性和方法的列表, 避免使用这些方法名定义自定义属性。

例如,假设有一个管理某些自定义字段的用户界面。 用户可以通过指定名称和值来添加自定义字段:

何时使用Map来代替普通的JS对象

将定制字段的状态存储到普通对象中会很方便:

const userCustomFields = {
  'color':    'blue',
  'size':     'medium',
  'toString': 'A blue box'
};

但是用户可能会选择一个自定义字段名称,例如toString(如示例中所示),构造函数等,这可能会破坏咱们的对象。

不要使用用户输入的值作为普通对象上键。

map没有这个问题,键值名称不受限制:

function isMap(value) {
  return value.toString() === '[object Map]';
}

const actorMap = new Map();

actorMap.set('name', 'Harrison Ford');
actorMap.set('toString', 'Actor: Harrison Ford');

// Works!
isMap(actorMap); // => true

不管actorMap有一个名为toString的属性,toString()方法都可以正常工作。

3. map 是可迭代

为了遍历普通对象的属性,必须使用其他的辅助静态函数,如Object.keys()或Object.entries():

const colorsHex = {
  'white': '#FFFFFF',
  'black': '#000000'
};

for (const [color, hex] of Object.entries(colorsHex)) {
  console.log(color, hex);
}
// 'white' '#FFFFFF'
// 'black' '#000000'

Object.entries(colorsHex)返回从对象提取的键值对数组。

但是,map本身是可迭代的:

const colorsHexMap = new Map();

colorsHexMap.set('white', '#FFFFFF');
colorsHexMap.set('black', '#000000');

for (const [color, hex] of colorsHexMap) {
  console.log(color, hex);
}
// 'white' '#FFFFFF'
// 'black' '#000000'

colorsHexMap是可迭代。可以在任何接受迭代的地方使用它:for()循环,展开运算符[...map]。

map提供了返回可迭代方法:map.keys()遍历键,map.values()遍历值

4. map 的大小

普通对象的另一个问题是,您无法立马知道它包含的属性的数量。

const exams = {
  'John Smith': '10 points',
  'Jane Doe': '8 points',
};

Object.keys(exams).length; // => 2

要确定exams的大小,必须通过所有键来确定它们的数量。

map 提供了 size 属性,表示属性的数量。

const examsMap = new Map([
  ['John Smith', '10 points'],
  ['Jane Doe', '8 points'],
]);
  
examsMap.size; // => 2

确定map的属性的数量更加简单:examsMap.size。

以上就是何时使用Map来代替普通的JS对象的详细内容,更多关于JS对象的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
Ext JS添加子组件的误区探讨
Jun 28 Javascript
jQuery使用之设置元素样式用法实例
Jan 19 Javascript
js焦点文字滚动效果代码分享
Aug 25 Javascript
学习JavaScript设计模式之策略模式
Jan 12 Javascript
jquery分页插件jquery.pagination.js实现无刷新分页
Apr 01 Javascript
js轮播图代码分享
Jul 14 Javascript
总结十个Angular.js由浅入深的面试问题
Aug 26 Javascript
vue打包后显示空白正确处理方法
Nov 01 Javascript
Vue中使用Sortable的示例代码
Apr 07 Javascript
webpack4 SCSS提取和懒加载的示例
Sep 03 Javascript
如何使用50行javaScript代码实现简单版的call,apply,bind
Aug 14 Javascript
实用的 vue tags 创建缓存导航的过程实现
Dec 03 Vue.js
详解Js模块化的作用原理和方案
详解JavaScript中的执行上下文及调用堆栈
JavaScript实现淘宝商品图切换效果
JavaScript实现显示和隐藏图片
Apr 29 #Javascript
JS Canvas接口和动画效果大全
Apr 29 #Javascript
JS ES6异步解决方案
Apr 29 #Javascript
聊聊JS ES6中的解构
Apr 29 #Javascript
You might like
PHP爆绝对路径方法收集整理
2012/09/17 PHP
php循环table实现一行两列显示的方法
2015/06/04 PHP
PHP设计模式(八)装饰器模式Decorator实例详解【结构型】
2020/05/02 PHP
HTML node相关的一些资料整理
2010/01/01 Javascript
ExtJS4 组件化编程,动态加载,面向对象,Direct
2011/05/12 Javascript
Javascript 面向对象(一)(共有方法,私有方法,特权方法)
2012/05/23 Javascript
不要使用jQuery触发原生事件的方法
2014/03/03 Javascript
Js数组排序函数sort()介绍
2015/06/08 Javascript
SpringMVC restful 注解之@RequestBody进行json与object转换
2015/12/10 Javascript
jQuery绑定事件-多种实现方式总结
2016/05/09 Javascript
Bootstrap源码解读网格系统(3)
2016/12/22 Javascript
nodejs acl的用户权限管理详解
2018/03/14 NodeJs
详解微信小程序之一键复制到剪切板
2019/04/24 Javascript
layui实现二维码弹窗、并下载到本地的方法
2019/09/25 Javascript
解决vue cli使用typescript后打包巨慢的问题
2019/09/30 Javascript
vue 组件开发原理与实现方法详解
2019/11/29 Javascript
[03:40]2014DOTA2国际邀请赛 B神专访:躲箭真的很难
2014/07/13 DOTA
[52:02]完美世界DOTA2联赛PWL S2 FTD.C vs SZ 第一场 11.27
2020/11/30 DOTA
Python可跨平台实现获取按键的方法
2015/03/05 Python
使用wxPython获取系统剪贴板中的数据的教程
2015/05/06 Python
Python实现一个转存纯真IP数据库的脚本分享
2017/05/21 Python
pandas 选择某几列的方法
2018/07/03 Python
wxpython自定义下拉列表框过程图解
2020/02/14 Python
CSS3 mask 遮罩的具体使用方法
2017/11/03 HTML / CSS
HTML5的文档结构和新增标签完全解析
2017/04/21 HTML / CSS
Javascript如何发送一个Ajax请求
2015/01/26 面试题
类和结构的区别
2012/08/15 面试题
UNIX特点都有哪些
2016/04/05 面试题
材料化学应届生求职信
2013/10/09 职场文书
白酒市场开发计划书
2014/01/09 职场文书
"9.18"国耻日演讲稿范文
2014/09/14 职场文书
庆六一开幕词
2015/01/29 职场文书
幼儿园奖惩制度范本
2015/08/05 职场文书
2016暑期社会实践新闻稿
2015/11/25 职场文书
巧用 -webkit-box-reflect 倒影实现各类动效(小结)
2021/04/22 HTML / CSS
MySQL批量更新不同表中的数据
2022/05/11 MySQL