使用 ECMAScript 2021 实现 JavaScript 的 hashmap 数据结构

引言

在前端开发中,数据结构是至关重要的一部分。HashMap 是一种重要的数据结构,在快速访问和处理大量数据时表现突出。JavaScript 原生提供了 Map 和 Set 两种集合类,但是没有提供类似HashMap的数据结构。本文将介绍如何使用 ECMAScript 2021 实现 HashMap 数据结构,并给出一些示例代码,以便读者更好地理解和实践。

HashMap 数据结构简介

HashMap 是一种基于关键码值(key-value)而进行访问的数据结构,通过把关键码值映射到数组中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

一个简单的 HashMap 的实现应该提供以下方法:

  • get(key):查询指定 key 对应的 value
  • put(key, value):插入一组 key-value
  • remove(key):删除指定 key 对应的 value
  • has(key):判断指定 key 是否存在

ECMAScript 2021 新特性

在先前的 ES6、ES7、ES8 版本中,JavaScript 已经提供了很多新特性来优化代码编写。而在 ECMAScript 2021 (ES12) 中,也提供了一些有助于优化 HashMap 实现的新特性:

Record 类型

Record 类型旨在为具有字符串键的对象提供纯类型定义。它可以用来定义具有确定属性集的 “数据记录” 的类型,这些属性集在对象生命周期内固定不变。我们可以借助 Record 对象简化代码并保证类型安全。

Record 的基本语法如下:

type Properties<T, V> = {
  [P in keyof T]: V;
};

type Record<K extends keyof any, T> = {
  [P in K]: T;
};

其中,Properties 和 Record 类型别名具有以下作用:

  • Properties<T, V> 类型别名定义了一个新类型:属性名称与 T 相同,属性的值类型为 V 的类型。
  • Record<K extends keyof any, T> 类型别名定义了一个新类型:属性名称为 K 的类型,并且属性值类型为 T。

下面是一个简单的示例:

type Person = {
  name: string;
  age: number;
};

type PersonMap = Record<string, Person>;

在上面的示例中,PersonMap 类型定义一个由字符串映射到 Person 对象的 HashMap。我们可以创建一个 PersonMap 类型对象,将其视为 HashMap 来使用。

Nullish 合并运算符

Nullish 合并运算符(??)为值为 null 或 undefined 的变量提供了一个更方便的默认值语法。它类似于逻辑或运算符 (||) ,但有两种不同之处:

  1. 当变量为 null 或 undefined 时,逻辑或运算符返回假值,而 Nullish 合并运算符返回这个变量自身。
  2. 当变量的值为假值(如 false 或者 0)时,逻辑或运算符将返回假值,而 Nullish 合并运算符返回这个变量自身的值。

下面是一个简单的示例,用来说明Nullish 合并运算符的用法。

const name = "";
const result = name ?? "default name"; // 返回默认值:default name

可选链运算符

在 ECMAScript 2020 规范中,JavaScript 引入了可选链运算符(? .)以使代码更简洁、可读性更高。可选链运算符允许我们检测及使用值可能为 null 或者 undefined 的对象的属性。在使用可选链运算符之前,我们可能需要使用 && 运算符进行 null 或 undefined 值的判断,现在可以使用可选链运算符更简化实现过程。

下面是一个示例,用来说明可选链运算符的使用方法。

const person = null;
const age = person?.age;

通过上述代码,我们可以避免了对 person 对象进行非空判断,大大增强了代码的可读性和可维护性。

使用 ECMAScript 2021 实现 HashMap

了解了 ECMAScript 2021 的新特性之后,就可以开始实现一个 HashMap 数据结构了。下面我们来实现一个简单的 HashMap 类:

type Record<K extends keyof any, T> = {
  [P in K]: T;
};

interface KeyValue<V> {
  key: string;
  value: V;
}

class HashMap<V> {
  private map: Record<string, KeyValue<V>> = {};

  get(key: string): V | undefined {
    const item = this.map[key];
    if (item === undefined) {
      return undefined;
    }
    return item.value;
  }

  put(key: string, value: V): void {
    this.map[key] = { key, value };
  }

  remove(key: string): void {
    delete this.map[key];
  }

  has(key: string): boolean {
    return this.map[key] !== undefined;
  }
}

在上述代码中,HashMap 类的实现非常简单,使用了 Record、KeyValue、interface 等 ECMAScript 2021 的新特性。对于 Record 类型的定义和上面的示例一致,KeyValue 类型用来存储 key-value 对。HashMap 类的主要方法是 get、put、remove 和 has,可以方便地查询、插入、删除和判断数据是否存在。

下面是一个简单的示例,使用 HashMap 在前端开发中存储数据:

const userMap = new HashMap<number>();
userMap.put("zhangsan", 18);
userMap.put("lisi", 20);
const age = userMap.get("zhangsan"); // 18
userMap.remove("lisi");
const exists = userMap.has("wangwu"); // false

通过这个示例,我们可以看到 HashMap 实现的简单性和易用性。HashMap 的实现代码也可以通过引入第三方库 Immutable.js 等方式来进一步优化和扩展。

总结

通过本文的介绍,我们了解了 HashMap 数据结构的基本概念和 JavaScript 中原生集合类 Map 和 Set 的用法。通过 ECMAScript 2021 的新特性和示例代码,我们学习了如何使用 ECMAScript 2021 来实现一个简单的 HashMap。上述示例是可参考的,并可以通过引入 Immutable.js 等第三方库来进一步优化和扩展代码实现。建议读者在日常项目开发中多熟悉和使用数据结构,提高代码运行效率与维护性。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a61ef4add4f0e0ffecbaee


纠错反馈