ES6 Map:为什么/何时使用对象或函数作为键?

15 javascript ecmascript-6

我已经阅读了Map的内容,并了解了Object与Map之间的区别.我不明白为什么我会使用objectsfunctions作为Map允许的键.

问题:为什么以及何时设置objectfunction作为密钥?

nem*_*035 6

基本上,如果您想要跟踪与对象相关的任何信息,这些信息由于某种原因而不应出现在对象本身上,则可以使用地图.

一个简单的例子可以是跟踪与对象相关的操作完成次数.

这是一个示范,我们跟踪每只动物(实例)吃了多少食物而不影响动物本身:

function Animal(type) {
  this.type = type;
}

// now let's say somewhere else in our program
// we want to have a farm where animals can eat.
// We want the farm to keep track of how much each animal ate but
// the animal itself doesn't need to know how much food it has eaten.
const AnimalFarm = (() => {
  const mapOfAnimalToAmountOfFood = new Map();
  return {
    feedAnimal(animal, amountOfFood) {
      // if the animal is being fed the first time
      // initialize the amount to 0
      if (!mapOfAnimalToAmountOfFood.has(animal)) {
        mapOfAnimalToAmountOfFood.set(animal, 0)
      }

      // add amountOfFood to the amount of food already eaten
      mapOfAnimalToAmountOfFood.set(
        animal,
        mapOfAnimalToAmountOfFood.get(animal) + amountOfFood
      )
    },
    getAmountEaten: function(animal) {
      return mapOfAnimalToAmountOfFood.get(animal)
    }
  }
})()

const dog1 = new Animal('dog')
const dog2 = new Animal('dog')

AnimalFarm.feedAnimal(dog1, 300)
AnimalFarm.feedAnimal(dog1, 500)
AnimalFarm.feedAnimal(dog2, 1234)

console.log(
  `dog1 ate ${AnimalFarm.getAmountEaten(dog1)} total`
)

console.log(
  `dog2 ate ${AnimalFarm.getAmountEaten(dog2)} total`
)
Run Code Online (Sandbox Code Playgroud)

通常,为某些数据创建对象映射的主要原因是您可以维护有关对象的本地信息,该对象虽然与此对象直接相关,但完全包含在您自己的模块中,并且不会污染任何其他部分.系统(关注点分离).

另一个例子可能是一个图表,其中有一个对象映射表示节点到他们有连接的其他节点的列表(例如在Dijkstra算法中很有用):

Map<Place, ListOfPlacesICanGoTo>
Run Code Online (Sandbox Code Playgroud)

这允许您通过分离此关系而不是在对象本身中放置直接链接来拥有更 的对象.如果在不需要甚至没有意义的其他环境中使用a,这尤其有用.PlacePlace.listOfPlacesPlacelistOfPlaces

对象作为类似地图结构中的键的另一种常见用法是使用a时WeakMap,因为只要没有其他任何引用它的每个键对象都被垃圾收集,它也可以提高内存效率.一个例子可能是process.on('unhandledRejection')in节点的底层实现,它使用aWeakMap来跟踪被拒绝的promise,但是没有错误处理程序处理当前tick中的拒绝.


至于使用函数作为键,我个人认为这不太有用,但肯定不是无用的.

一个有用的示例可能是检查某个函数之前是否已经传入,而不是再次调用它,而是返回一个缓存的结果.这可以防止重复执行可能昂贵的操作.

const map = new Map();
function invokeOrGetFromCache(fn) {
  if (map.has(fn)) {
    return map.get(fn);
  }
  const result = fn();
  map.set(fn, result);
  return result;
}

function exampleFn() {
  console.log('start');
  for (i = 0; i < 100000; i++);
  console.log('done');
  return true;
}

console.log(
  invokeOrGetFromCache(exampleFn) // runs exampleFn
);

console.log(
  invokeOrGetFromCache(exampleFn) // retrieves from cache
);
Run Code Online (Sandbox Code Playgroud)

与对象WeakMap一样,出于效率原因,在这些情况下使用a 也是优选的.