ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Map和WeakMap

2020-12-13 10:33:30  阅读:284  来源: 互联网

标签:Map WeakMap Person 键值 key prototype


Map和WeakMap

Map

JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键,是一种更完善的 Hash 结构实现。

生成Map实例:

const map1 = new Map();
const map2 = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);

Map 实例的属性:

  • Map.prototype.size:返回Map实例的成员总数。

Map实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。

四个操作方法:

  • Map.prototype.set(key,value):设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。
  • Map.prototype.get(key):读取key对应的键值,如果找不到key,返回undefined
  • Map.prototype.has(key):返回一个布尔值,表示某个键是否在当前 Map 对象之中。
  • Map.prototype.delete(key):删除某个键,返回true。如果删除失败,返回false
  • Map.prototype.clear():清除所有成员,没有返回值。

四个遍历方法:

  • Map.prototype.keys():返回键名遍历器
  • Map.prototype.values():返回键值遍历器
  • Map.prototype.entries():返回键值对遍历器
  • Map.prototype.forEach():使用回调函数遍历每个成员

实例1:扩展对象

当我们有一系列对象,想记录每个对象一种属性。假设有100只鸡,需要记录每只鸡的重量,有两种思路:

  1. 想办法用笔写到鸡身上
  2. 记录到一个本本上
class Chicken {
}
// 100只鸡
let chickenList = []
for (let i = 0; i < 100; i++) {
  chickenList.push(new Chicken())
}
                   
// 方法1:记录到鸡身上
chickenList.forEach(function(chicken, index){
	chicken.weight = getWeight(chicken);
});

// 方法2:记录到本本上
let notebook = [];
chickenList.forEach(function(chicken, index){
	notebook[index] = getWeight(chicken);
});

第1种思路存在以下问题:

  1. 破坏了鸡的卖相,有时候这是很严重的事情,比如你想把一只5斤的鸡当成6斤卖出去,结果鸡身上直接写“我只有5斤”(修改了原有对象,可能导致意外的行为)
  2. 可能碰到一些战斗鸡,一个字都写不上去(对象冻结了或者有不可覆盖的属性)
  3. 可能写到一些本来就写了字的地方,导致根本看不清(与对象原有属性冲突)

再看第2种方法,存在以下问题:

  1. 本本无法和鸡精准地一一对应,只能靠一些索引或者标记(例如给每只鸡起一个名字)去(不可靠)地记录对应关系(无法精准地对比到是哪一个对象)
    这时候就可以使用Map扩展对象
// 记录到另一个本本上
let notebook = new Map();
chickenList.forEach(function(chicken, index){
	notebook.set(chicken, getWeight(chicken));
});

实例2:完善私有属性的实现

回顾之前的Symbol实现的私有属性的版本里,仍然存在着可以被特殊api遍历的缺陷。

基于Map的解决思路:

用一个闭包内的Map来扩展每个生成的对象

var Person = (function() {
  var map = new Map();

  function Person(name) {
    map.set(this,name);
  }

  Person.prototype.getName = function() {
    return map.get(this);
  };

  return Person;
}());

WeakMap

与之前介绍的WeakSet 类似,WeakMapMap 有两个区别。

  • WeakMap的键只能是对象,而不能是其他类型的值。
  • WeakMap 中对键的引用是弱引用

同样地,WeakMap 不能遍历,是因为成员都是弱引用,随时可能消失。

WeakMap只有四个方法可用:get()set()has()delete()

注意:WeakMap 弱引用的只是键名,而不是键值。键值依然是正常引用。

const wm = new WeakMap();
let key = {};
let obj = {foo: 1};

wm.set(key, obj);
obj = null;
wm.get(key)

实例:完善私有属性的实现

前面基于Map的实现还存在一个问题:

Person实例的外部引用消除时,闭包中的Map仍然有Person实例作为键的引用,Person实例不会被垃圾回收,必须等到所有的Person实例的外部引用消除,Map所在的闭包也会消除,最后Person实例才会被垃圾回收

为了解决这个问题,使用WeakMap进一步完善:

var Person = (function() {
  var wm = new WeakMap();

  function Person(name) {
    wm.set(this,name);
  }

  Person.prototype.getName = function() {
    return wm.get(this);
  };

  return Person;
}());

标签:Map,WeakMap,Person,键值,key,prototype
来源: https://www.cnblogs.com/xm0328/p/14127962.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有