ES6-JS的第六种基本数据类型Symbol

169 阅读3分钟

前言

  在ES6之前,Object对象的属性名只能是字符串,在引用他人提供的对象,并为对象添加新属性的过程中,很容易出现属性名冲突。为了解决这个问题,ES6 引入了一种新的原始数据类型 Symbol

  Symbol表示独一无二的值,最大的用法是用来定义对象的唯一属性名,它是JavaScript的第六种基本数据类型(stringnumberbooleanundefinednullSymbol)。在此之后,对象的属性名可以有两种类型:字符串 / Symbol

一、Symbol类型的创建

理解: Symbol 是基本数据类型而并非对象,因此无法通过 new 的方式创建,Symbol可以通过Symbol()函数生成。

  // 创建symbol
  const symbol =Symbol();
  console.log(symbol);          // 输出:Symbol()
  console.log(typeof(symbol));  // 输出:symbol

参数: Symbol函数接收一个字符串作为参数,用于为新创建的 Symbol 提供描述,用来显示在控制台或者作为字符串的时候使用,便于区分。

  const symbol =Symbol("描述");
  console.log(symbol);          // 输出:Symbol(描述)

注意: Symbol函数的描述只表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。

  const symbol1 = Symbol("稀土掘金");
  const symbol2 = Symbol("稀土掘金");
  console.log(symbol1 === symbol2); // 输出:false

二、Symbol的特点

1. Symbol 的值是唯一的,所以不存在命名冲突

  let obj = {
    [Symbol("稀土掘金")]: "Very",
    [Symbol("稀土掘金")]: "Cool",
  };
  console.log(obj); // 输出:{Symbol(稀土掘金): 'Very', Symbol(稀土掘金): 'Cool'}

2. Symbol 值不能与其他数据进行运算

  const symbol = Symbol("稀土掘金");
  const num = 666 + symbol;
  const str = "VeryCool" + symbol;
  console.log(num); // 输出:Cannot convert a Symbol value to a number
  console.log(str); // 输出:Cannot convert a Symbol value to a string

3. Symbol的读取方式

注意: Symbol 值作为属性名时,该属性是公有属性不是私有属性,可以在类的外部访问。

但是 Symbol 无法通过 for...infor...of 读取,也不会被 Object.keys()Object.getOwnPropertyNames() 返回。

  let obj = {
    name: "VeryCool",
    age: 18,
    [Symbol("like")]: "稀土掘金",
  };
  // for...in
  for(let item in obj) {
    console.log(item);  // 输出: name  age    不输出:like
  }
  // for...of
  for(let item of obj) {
    console.log(item);  // 输出: obj is not iterable
  }
  // Object.keys()
  console.log(Object.keys(obj));  // 输出:['name', 'age']
  // Object.getOwnPropertyNames()
  console.log(Object.getOwnPropertyNames(obj));  // 输出:['name', 'age']

如果要读取一个对象的 Symbol 属性,可以通过 Object.getOwnPropertySymbols()Reflect.ownKeys() 读取。

  let obj = {
    name: "VeryCool",
    age: 18,
    [Symbol("like")]: "稀土掘金",
  };
  // Object.getOwnPropertySymbols()方法专门用来读取symbol
  console.log(Object.getOwnPropertySymbols(obj));        // 输出:[Symbol(like)]
  // Reflect.ownKeys()方法可以读取包含symbol的所有属性
  console.log(Reflect.ownKeys(obj));            //  输出:['name', 'age', Symbol(like)]

三、Symbol的使用场景

作用: 因为每一个 Symbol 的值都是不相等的,所以 Symbol 作为对象的属性名,可以保证属性不重名。

  const symbol = Symbol();

  // 第一种写法
  const obj = {};
  obj[symbol] = "VeryCool";

  // 第二种写法
  const obj = {
    [symbol]: "VeryCool",
  };

  // 第三种写法
  const obj = {};
  Object.defineProperty(obj, symbol, { value: "VeryCool" });

  // 以上写法结果都如下
  const obj = {
    Symbol(): "VeryCool"
  }

四、Symbol的API

Symbol.for()

Symbol.for()类似单例模式,首先会在全局搜索被登记的 Symbol 中是否有该字符串参数作为名称的 Symbol 值,如果有即返回该 Symbol 值,若没有则新建并返回一个以该字符串参数为名称的 Symbol 值,并登记在全局环境中供搜索。

Symbol.for("bar") === Symbol.for("bar")   // true

Symbol("bar") === Symbol("bar")           // false

Symbol.keyFor()

Symbol.keyFor() 返回一个已登记的 Symbol 类型值的 key ,用来检测该字符串参数作为名称的 Symbol 值是否已被登记。

  const symbol1 = Symbol.for("稀土掘金");
  Symbol.keyFor(symbol1); // "稀土掘金"

  const symbol2 = Symbol("稀土掘金");
  // (变量symbol2属于未登记的 Symbol 值,所以返回undefined)
  Symbol.keyFor(symbol2); // undefined 

(文章参考自阮一峰ECMAScript 6入门)

结尾.jpg