编程语言都具有内建的数据结构,但各种编程语言的数据结构常有不同之处。本文我们一起来看看js内建的数据结构及其属性。
数据结构是计算机存储、组织数据的方式。数据结构意味着接口或封装:一个数据结构可被视为两个函数之间的接口,或者是由数据类型联合组成的存储内容的访问方法封装。直白讲,数据结构是数据的存储方式。js中常见的数据结构主要有以下:
- 数组
数组是最简单、也是使用最广泛的数据结构。数组是可以在内存中连续存储多个元素的结构,在内存中的分配也是连续的,数组中的元素通过数组下标进行访问,数组下标从0开始。此处不做过多解释。 - 栈
先进后出(FILO: First In Last Out)后进先出(LIFO:Last In First Out) - 队列
先进先出(FIFO: First In First Out)
队列只能在队尾插入元素,在队首删除元素
堆
堆(heap) 是一种特殊的基于树的数据结构。堆可以被看做一棵树的数组对象。
堆总是满足下列性质:
堆中某个节点的值总是不大于或不小于其父节点的值;堆是一棵完全二叉树。
根据其数值大小,可以分为大顶堆和小顶堆。
大顶堆:每个节点的值都大于或者等于它的左右子节点的值
小顶堆:每个节点的值都小于或者等于它的左右子节点的值
- 链表
数据元素的线性集合, 元素的线性顺序不是由它们在内存中的物理位置给出的。相反, 每个元素指向下一个元素。它是由一组节点组成的数据结构,这些节点一起,表示序列。
树
树是一种抽象数据类型(Abstract Data Type,简称ADT),模拟分层树结构, 具有根节点和有父节点的子树,表示为一组链接节点。
无序树
二叉树
特点是每个节点最多两个节点,左子树始终小于父节点,右子树始终大于父节点。二叉搜索树最常用的功能应该是遍历了。
前序遍历:6 3 2 7 5 8
中序遍历:2 3 6 5 7 8
后序遍历:2 3 6 7 8 5
前中后的顺序是根据父节点的顺序来定,然后子节点按照从左至右的方式遍历
哈希表
是一种实现 关联数组(associative array) 的抽象数据;类型, 该结构可以将键映射到值。
图
图(graph) 是一种抽象数据类型, 旨在实现数学中的无向图和有向图概念,特别是图论领域,感兴趣的同学可以自行查阅资料。
数据类型
了解了数据结构,我们再来看看js都有哪些数据类型,以及数据类型都是如何存储的?
JavaScript 是一种弱类型或者说动态语言。这意味着不用提前声明变量的类型,在程序运行过程中,类型会被自动确定,这也意味着我们可以使用同一个变量保存不同类型的数据。比如
var a; // 定义变量a 未明确类型
a = 1; // a此时为数字
a = true; // a此时为布尔值
a = 'string' // a此时为字符串
数据类型是一组性质相同的值的集合以及定义在这个值集合上的操作方法的综合, js数据类型根据其数据存储单元划分为原始数据类型(也叫基本数据类型)和引用数据类型。
基本数据类型
- undefined: typeof instance === "undefined"
- Boolean: typeof instance === "boolean"
- Number: typeof instance === "number"
- String: typeof instance === "string
- BigInt: typeof instance === "bigint"
- Symbol: typeof instance === "symbol"
- null: typeof instance === "object"
引用数据类型
- Object typeof instance === "undefined"
基本数据类型的特点:
基本类型的访问是按值访问的,就是说你可以操作保存在变量中的实际的值
- 基本数据类型的值是不可变得
var a = 1;
a.toString();
b = a.toString()
console.log(a) // 数字1
console.log(b) // 字符串
- 基本类型的比较是值的比较
var a = 1, b = true, c = 1;
a == b // true (==比较两个不同类型的变量时会进行一些类型转换 )
a === b // false
a === c // true (无需隐式转化)
- 基本类型的变量是存放在栈区的(栈区指内存里的栈内存,栈区内存由编译器自动分配释放)
引用数据类型的特点:
引用类型可以拥有属性和方法,属性又可以包含基本类型和引用类型
- 引用类型的值是可变的
var a = {}, b = [];
a.name = 'dynic';
b[0] = 'male';
console.log(a); // {name: 'dynic'}
console.log(b); // ['male']
- 引用类型的比较是引用的比较
var person1 = '{}',
person2 = '{}',
person3 = {},
person4 = {};
console.log(person1 == person2); // true
console.log(person1 == person3); // false
console.log(person3 == person4); // false
- 引用类型的值是同时保存在栈内存和堆内存中的对象,堆区内存一般由程序员分配释放,若程序员不释放,程序结束时可能由垃圾回收机制回收。
- 对象引用当从一个变量向另一个变量赋值引用类型的值时,同样也会将存储在变量中的对象的值复制一份放到为新变量分配的空间中。保存在变量中的是对象在堆内存中的地址,所以,与简单赋值不同,这个值的副本实际上是一个指针,而这个指针指向存储在堆内存的一个对象。那么赋值操作后,两个变量都保存了同一个对象地址,则这两个变量指向了同一个对象。因此,改变其中任何一个变量,都会相互影响。通俗讲就是copy引用数据之后,会改变被copy的值。(可自行查阅浅copy与深copy之前的区别)
var a = {};
var b = a;
b.sex = 'male';
console.log(a); // {sex: 'male'}
console.log(b); // {sex: 'male'}
以上就是有关js数据类型和数据结构相关的内容,相关算法我们会在后面一一进行讲解。下一篇文章我们会对js面向对象的继承特性进行总结与学习,敬请期待。留一道思考题,如何实现深copy?