何时使用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 相关文章推荐
根据分辨率不同,调用不同的css文件
Aug 25 Javascript
jquery ui dialog里调用datepicker的问题
Aug 06 Javascript
学习ExtJS(二) Button常用方法
Oct 07 Javascript
JS维吉尼亚密码算法实现代码
Nov 09 Javascript
jquery插件开发方法(初学者)
Feb 03 Javascript
javascript基本算法汇总
Mar 09 Javascript
javascript中Number的方法小结
Nov 21 Javascript
JavaScript箭头函数_动力节点Java学院整理
Jun 28 Javascript
element-ui 限制日期选择的方法(datepicker)
May 16 Javascript
vue里面使用mui的弹出日期选择插件实例
Sep 16 Javascript
vue路由传参页面刷新参数丢失问题解决方案
Oct 08 Javascript
JS实现放大镜效果
Sep 21 Javascript
详解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判断服务器是否支持Gzip压缩功能
2013/09/24 PHP
php fsockopen解决办法 php实现多线程
2014/01/20 PHP
PHP利用imagick生成组合缩略图
2016/02/19 PHP
php仿微信红包分配算法的实现方法
2016/05/13 PHP
中高级PHP程序员应该掌握哪些技术?
2016/09/23 PHP
PHP防止图片盗用(盗链)的方法小结
2016/11/11 PHP
win10下 php安装seaslog扩展的详细步骤
2020/12/04 PHP
用tip解决Ext列宽度不够的问题
2008/12/13 Javascript
从盛大通行证上摘下来的身份证验证js代码
2011/01/11 Javascript
点击弹出层效果&弹出窗口后网页背景变暗效果的实现代码
2014/02/10 Javascript
js与运算符和或运算符的妙用
2014/02/14 Javascript
jQuery实现图片左右滚动特效
2020/04/20 Javascript
JS实现带有3D立体感的银灰色竖排折叠菜单代码
2015/10/20 Javascript
Jquery表单验证失败后不提交的解决方法
2016/10/18 Javascript
javascript ES6中箭头函数注意细节小结
2017/02/17 Javascript
Vue中添加过渡效果的方法
2017/03/16 Javascript
详解vue组件化开发-vuex状态管理库
2017/04/10 Javascript
JavaScript中引用vs复制示例详析
2018/12/06 Javascript
[01:11:46]DOTA2-DPC中国联赛 正赛 iG vs Magma BO3 第一场 2月23日
2021/03/11 DOTA
Python读取键盘输入的2种方法
2015/06/16 Python
Python3中的真除和Floor除法用法分析
2016/03/16 Python
Python实现在某个数组中查找一个值的算法示例
2018/06/27 Python
Python3爬虫学习之将爬取的信息保存到本地的方法详解
2018/12/12 Python
Django 自定义404 500等错误页面的实现
2020/03/08 Python
如何利用Python动态模拟太阳系运转
2020/09/04 Python
Pycharm常用快捷键总结及配置方法
2020/11/14 Python
Html5应用程序缓存(Cache manifest)
2018/06/04 HTML / CSS
金牌葡萄酒俱乐部:Gold Medal Wine Club
2017/11/02 全球购物
构造方法和其他方法的区别?怎么调用父类的构造方法
2013/09/22 面试题
报效祖国演讲稿
2014/09/15 职场文书
员工评语范文
2014/12/31 职场文书
交通事故被告代理词
2015/05/23 职场文书
2016年“5.12”护士节慰问信
2015/11/30 职场文书
学法用法心得体会(2016推荐篇)
2016/01/21 职场文书
详解RedisTemplate下Redis分布式锁引发的系列问题
2021/04/27 Redis
Python爬虫之用Xpath获取关键标签实现自动评论盖楼抽奖(二)
2021/06/07 Python