不常见的数据类型
这里是一些不常见的数据类型
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...in、for...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..of 或 forEach 来遍历 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 中)