前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript 对象与 Hash 表

JavaScript 对象与 Hash 表

作者头像
李振
发布2021-11-26 14:50:20
1.9K0
发布2021-11-26 14:50:20
举报
文章被收录于专栏:乱码李

简介

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

JavaScript 中的对象也是以 Key-Value 的形式访问,那么 JavaScript 的对象是否以 Hash 的结构存储呢?

我们首先来看一下 Hash 表结构。

Hash 表结构

数组的特点是:寻址容易,插入和删除困难;而链表的特点是:寻址困难,插入和删除容易,Hash 表综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构。

下图是最常见的 拉链法 做出的 Hash 表

左边是一个数组,数组的每个成员包括一个指针,指向一个链表的头,当然这个链表可能为空,也可能元素很多。我们根据元素的一些特征把元素分配到不同的链表中去,也是根据这些特征,找到正确的链表,再从链表中找出这个元素。

元素特征转变为数组下标的方法就是散列法。上图运用的方法为 整除法,公式为:

index = value % 16

hash表的工作原理:

  1. 第一步 先根据给定的key和散列算法得到具体的散列值,也就是对应的数组下标。
  2. 第二步,根据数组下标得到此下标里存储的指针,若指针为空,则不存在这样的键值对,否则根据此指针得到此链式数组。
  3. 遍历此链式数组,分别取出Key与给定的Key比较,若找到与给定key相等的Key,即在此hash表中存在此要查找的<Key,Value>键值对,此后便可以对此键值对进行相关操作;若找不到,即为不存在此键值对。

JavaScript 对象存储形式

JavaScript 对象 Key 存储形式

在我们创建或者访问对象属性的时候,如果使用 对象.属性名 的方式,属性名只能为字符串类型,而且不能以数字开头:

代码语言:javascript
复制
let obj = {};
obj.2 = 2;  //Uncaught SyntaxError: Unexpected number
obj.12s = '12s';  //Uncaught SyntaxError: Invalid or unexpected token

而使用字面量的形式创建对象,或者用 对象[属性名] 的方法,却没有这样的限制:

代码语言:javascript
复制
let o = {};
let obj = {
    x: 1,
    2: 2,
    o: 'object',
    {name: 'Leo'}: 'object'
};
obj['12s'] = '12s';
obj[{name: 'Leo'}] = 'object'; //使用 对象[属性名] 的方式甚至可以把对象当做属性名传入

此时 obj 里面的属性 2 是一个整数吗?

代码语言:javascript
复制
for (let i in obj) {
    console.log(typeof i, i, obj[i]);
}
// string 2 2
// string x 1
// string o object
// string 12s 12s
// string [object Object] object

由此可见 JavaScript 中对象的 Key 均是 string 类型。

代码语言:javascript
复制
console.log(obj[2] === obj['2']);  // true
object[2]=3;
console.log(object['2']);//3

可见解释器在访问 object[2] 的时候,先将方括号里面的 2 转换成字符串,然后再访问。

而使用 obj[{name: ‘Leo’}] = ‘object’ 的时候,也是同样的,解释器先调用 Objcet.toString 方法把对象 {name: ‘Leo’} 转换成字符串,然后再访问。

代码语言:javascript
复制
let object = {
  x: 1,
  2: 2
}
Object.prototype.toString = function () {
  return '2';
}
console.log(object[{name: 'Leo'}]);  // 2

上述的 object[{name: ‘Leo’}] 相当于 object[{name: ‘Leo’}.toString()] 亦相当于 object[‘2’],于是就得到结果 2。

这里也间接证明了 JavaScript 对象中,所有的 key 都是字符串,即使你访问的时候不是字符串的形式,解释器也会先将其转化为字符串。

可是我们知道整数值直接调用 toString 方法是会报错的,因为 JavaScript 解析器会试图将点操作符解析为浮点数字面值的一部分。不过有很多变通方法可以让数字的字面值看起来像对象。

代码语言:javascript
复制
2.toString() // Uncaught SyntaxError: Invalid or unexpected token
//解决方案
2..toString(); // 第二个点号可以正常解析
2 .toString(); // 注意点号前面的空格
(2).toString(); // 2先被计算

所以 JavaScript 解释器应该有帮我们做这一部分工作。

JavaScript 对象 Value 存储形式

在JavaScript高级程序设计(第三版)中,是这么描述属性的:属性在创建时都带有一些特征值,JavaScript引擎通过这些特征值来定义他们的行为。

代码语言:javascript
复制
var person = {};
person.name = 'Leo';
var descriptor=Object.getOwnPropertyDescriptor(person,"name");
console.log(descriptor); 
//Object
	// configurable: true
	// enumerable: true
	// value: "Leo"
	// writable: true
	// __proto__: Object

可见 value 的数据类型是结构体。

JavaScript 对象存储形式

在 JavaScript 中,我们可以任意给对象添加或者删除属性,由此可以推断,对象不是由数组结构存储;链表虽然能够任意伸缩但是其查询效率低下,因此也排除链表。如果用树作为存储结构,效率较高的可能就是平衡树了。平衡树的查询效率还可以接受,但是当删除属性的时候,平衡树在调整的时候代价相比于 hash 表要大很多。于是 Hash 成为最好的选择。

假如有这么一段代码:

代码语言:javascript
复制
function Person(id, name, age) {
	this.id = id;
	this.name = name;
	this.age = age;
}
let num = 10;
let bol = true;
let obj = new Object;
let arr = ['a', 'b', 'c'];
let person = new Person(100, 'Leo', 18);

JavaScript 内存分析图 如下:

变量 num、bol、str 为基本数据类型,它们的值直接存放在栈中。obj、person、arr 为复合数据类型,他们的引用变量存储在栈中,指向于存储在堆中的实际对象。

在 JavaScript 中变量分为基本类型和引用类型(对象类型),分别对应着两种不同的存储方式–栈存储和堆存储。

基本类型一旦初始化则内存大小固定,访问变量就是访问变量的内存上实际的数据,称之为按值访问。而对象类型内存大小不固定,无法在栈中维护,所以 JavaScript 就把对象类型的变量放到堆中,让解释器为其按需分配内存,而通过对象的引用指针对其进行访问,因为对象在堆中的内存地址大小是固定的,因此可以将内存地址保存在栈内存的引用中。这种方式称之为按引用访问。

总结

在 JavaScript 中对象是以 Hash 结构存储的,用 <Key, Value> 键值对表示对象的属性,Key 的数据类型为字符串,Value 的数据类型是结构体,即对象是以 <String, Object> 类型的 HashMap 结构存储的。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-12-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
    • Hash 表结构
    • JavaScript 对象存储形式
      • JavaScript 对象 Key 存储形式
        • JavaScript 对象 Value 存储形式
          • JavaScript 对象存储形式
          • 总结
          相关产品与服务
          对象存储
          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档