映射

我们在上一章中看到了映射(map)这个词,用于一个操作,通过对元素应用函数来转换数据结构。 令人困惑的是,在编程时,同一个词也被用于相关而不同的事物。

映射(名词)是将值(键)与其他值相关联的数据结构。 例如,你可能想要将姓名映射到年龄。 为此可以使用对象。

  1. let ages = {
  2. Boris: 39,
  3. Liang: 22,
  4. Júlia: 62
  5. };
  6. console.log(`Júlia is ${ages["Júlia"]}`);
  7. // → Júlia is 62
  8. console.log("Is Jack's age known?", "Jack" in ages);
  9. // → Is Jack's age known? false
  10. console.log("Is toString's age known?", "toString" in ages);
  11. // → Is toString's age known? true

在这里,对象的属性名称是人们的姓名,并且该属性的值为他们的年龄。 但是我们当然没有在我们的映射中列出任何名为toString的人。 似的,因为简单对象是从Object.prototype派生的,所以它看起来就像拥有这个属性。

因此,使用简单对象作为映射是危险的。 有几种可能的方法来避免这个问题。 首先,可以使用null原型创建对象。 如果将null传递给Object.create,那么所得到的对象将不会从Object.prototype派生,并且可以安全地用作映射。

  1. console.log("toString" in Object.create(null));
  2. // → false

对象属性名称必须是字符串。 如果你需要一个映射,它的键不能轻易转换为字符串 - 比如对象 - 你不能使用对象作为你的映射。

幸运的是,JavaScript 带有一个叫做Map的类,它正是为了这个目的而编写。 它存储映射并允许任何类型的键。

  1. let ages = new Map();
  2. ages.set("Boris", 39);
  3. ages.set("Liang", 22);
  4. ages.set("Júlia", 62);
  5. console.log(`Júlia is ${ages.get("Júlia")}`);
  6. // → Júlia is 62
  7. console.log("Is Jack's age known?", ages.has("Jack"));
  8. // → Is Jack's age known? false
  9. console.log(ages.has("toString"));
  10. // → false

setgethas方法是Map对象的接口的一部分。 编写一个可以快速更新和搜索大量值的数据结构并不容易,但我们不必担心这一点。 其他人为我们实现,我们可以通过这个简单的接口来使用他们的工作。

如果你确实有一个简单对象,出于某种原因需要将它视为一个映射,那么了解Object.keys只返回对象的自己的键,而不是原型中的那些键,会很有用。 作为in运算符的替代方法,你可以使用hasOwnProperty方法,该方法会忽略对象的原型。

  1. console.log({x: 1}.hasOwnProperty("x"));
  2. // → true
  3. console.log({x: 1}.hasOwnProperty("toString"));
  4. // → false