Skip to main content

不常见的数据类型

这里是一些不常见的数据类型

Symbol

可以创建一个唯一的值

new Symbol();
// Uncaught TypeError: Symbol is not a constructor
const symbol1 = Symbol("lucas");
const symbol2 = Symbol("lucas");
symbol1 !== symbol2; // true

js 运行过程会设置一个全局 Symbol 注册表,可以通过Symbol.for(key)检索指定 key 的 Symbol 值

使用场景

  • 定义常量(枚举)
  • 对象私有属性。需要注意的是:遍历对象的时候,该属性不会出现在 for...infor...of 循环中,也不会被 Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回,可以用 Object.getOwnPropertySymbols() 获取
  • 实现一个可遍历的对象
const obj = {
from: 0,
to: 10,
[Symbol.iterator]: function () {
return {
current: this.from,
last: this.to,
next() {
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
},
};
},
};

for (let num of obj) {
console.log(num);
}
  • 其他内置 Symbol
    • Symbol.match
    • Symbol.toPrimitive

BigInt

可以用任意精度表示整数,并且可以正确执行整数运算而不会溢出。同为 BigInt 类型的变量才能做运算,并且 BigInt 永远不会等于 Number

new BigInt(5);
// Uncaught TypeError: BigInt is not a constructor
5n === BigInt(5);

const previousMaxSafe = BigInt(Number.MAX_SAFE_INTEGER);
// 9007199254740991n
const maxPlusOne = previousMaxSafe + 1n;
// 9007199254740992n

BigInt(1.5);
// RangeError
BigInt("1.5");
// SyntaxError

// 注意这里的类型转换
typeof 1n === "bigint"; // true
typeof BigInt("1") === "bigint"; // true

但要注意运算符有使用局限,比如不能用单目运算符、不能使用无符号右移等,详见 BigInt-MDN

Map

Map 跟普通对象的区别是不限键类型,并且是有序的

  • new Map()
  • map.set(key, value)
  • map.get(key)
  • map.has(key)
  • map.delete(key)
  • map.clear()
  • map.size
const map = new Map();
map.set("1", "lucas");
map.set(1, "gogogo");
console.log(map.get(1)); // 'gogogo'
console.log(map.get("1")); // 'lucas'
console.log(map.size); // 2
const obj = { name: "lucas" };
map.set(obj, "gogogo");

将对象转换成 Map 对象

const prices = new Map([
["banana", 1],
["orange", 2],
["meat", 10],
]);

使用 Object.fromEntries 将 Map 对象转换成一个普通对象

const prices = Object.fromEntries([
["banana", 1],
["orange", 2],
["meat", 10],
]);
// prices: { banana: 1, orange: 2, meat: 10 }

遍历 Map 对象可以用 map.keys()/map.values()/map.entrie()

Set

Set 跟普通数组的区别主要在于唯一,并且没有下标的概念

  • new Set(iterable)
  • set.add(value)。返回 Set 对象本身
  • set.delete(value)。删除值,如果 value 在这个方法调用的时候存在则返回 true ,否则返回 false
  • set.has(value)
  • set.clear()
  • set.size
let set = new Set();
let a = { name: "a" };
let b = { name: "b" };
let c = { name: "c" };
set.add(a);
set.add(b);
set.add(c);
set.add(a);
set.add(b);
alert(set.size); // 3

可以使用 for..offorEach 来遍历 Set。除此之外,也可以用 set.keys()/set.values()/set.entrie() 实现遍历

let set = new Set(["oranges", "apples", "bananas"]);
set.forEach((value, valueAgain, set) => {
// 这里的三个参数,前两者是一样的。注意下标是数组特有的东西
console.log(value, valueAgain);
});

WeakMap

WeakMap 只能接受对象作为键,并保持了对键名所引用的对象的弱引用,在没有其他引用和该键引用同一对象,这个对象将会被垃圾回收(相应的 key 则变成无效的)

WeakSet

WeakSet 只能接受对象作为值,并且储存的对象都是被弱引用的,如果没有其他的变量或属性引用这个对象值,则这个对象将会被垃圾回收掉(不考虑该对象还存在于 WeakSet 中)

参考