十、Symbol数据类型

郁子大约 4 分钟约 1073 字笔记ECMAScript尚硅谷李强

(一)Symbol 简介

  • JS 的第七种数据类型,表示独一无二的值
    • Symbol 值唯一,用于解决命名冲突的问题
    • Symbol 值不能与其他数据进行运算【四则运算、字符串拼接、大小比较等】
    • Symbol 定义的对象属性不能使用 for...in 循环遍历,但是可以使用 Reflect.ownKeys 来获取对象的所有键名
  • JS 所有数据类型:USONB => you are so nubility
    • U: undefined
    • S: stringsymbol
    • O: object
    • N: nullnumber
    • B: boolean

1.创建 Symbol

  • 内部实现了唯一性,外部不可见
  • Symbol 是一个函数对象

1)方式一:Symbol 是一个函数

  • Symbol()
let s = Symbol();
console.log(s, typeof s);
// Symbol() 'symbol'

2)方式二:Symbol 是一个函数

  • 传入一个描述性字符串,用于区分所定义的 Symbol 变量
  • 标注当前 Symbol 变量的作用/意义,只是一个标志但是返回结果不同
let s2 = Symbol("ikuko");
let s3 = Symbol("ikuko");
console.log(s2 === s3);
// false

3)方式三:Symbol 是一个对象

  • 通过 .for() 创建的 Symbol 对象
  • 可以通过传入的字符串得出唯一的 Symbol
let s4 = Symbol.for("ikuko");
console.log(s4, typeof s4);
// Symbol(ikuko) 'symbol'

let s5 = Symbol.for("ikuko");
let s6 = Symbol.for("yg");
console.log(s4 === s5, s4 === s6);
// true false

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

let r1 = s + 100;
let r2 = s > 100;
let r3 = s + "100";
let r4 = s + s;
// Cannot convert a Symbol value to a number

(二)Symbol 创建对象属性

  • 使用 Symbol 给对象添加属性或方法,确保独一无二
// 向对象中添加方法 up down
// 该对象结构较复杂,无法判断对象内部是否已经有up或down方法
let game = {
  name: "2048",
  up() {
    console.log("自带的up方法");
  },
  down() {
    console.log("自带的down方法");
  },
};

// 以下写法有风险:如果对象内部有同名方法,会造成冲突
game.up = function () {};
game.down = function () {};

1.方式一:声明一个对象

let methods = {
  up: Symbol(),
  down: Symbol(),
};
game[methods.up] = function () {
  console.log("我可以改变形状。");
};
game[methods.down] = function () {
  console.log("我可以快速下降。");
};
console.log(game);
// {name: '2048', up: ƒ, down: ƒ, Symbol(): ƒ, Symbol(): ƒ}

2.方式二:使用 Symbol

let youxi = {
  name: "狼人杀",
  // Symbol(): function() {}
  // 报错,因为【Symbol()不是一个固定属性,是动态值,是一个表达式】

  // [Symbol()]: function(){}
  [Symbol("say")]: function () {
    console.log("我可以发言。");
  },
  [Symbol("zibao")]: function () {
    console.log("我可以自爆。");
  },
};
console.log(youxi);
// {name: '狼人杀', Symbol(say): ƒ, Symbol(zibao): ƒ}

(三)Symbol 内置值

  • ES6 可以定义自己使用的 Symbol
    • 还提供了 11 个内置的 Symbol
    • 指向语言内部使用的方法
  • Symbol 内置值: Symbol.XXX
    • 其中 XXX 就是 Symbol 对象的属性
    • Symbol.XXX 整体又作为 Symbol 声明的对象的属性
    • 使用内置值可以改变 Symbol 对象在特定场景下的表现结果,扩展对象功能
  • 这些内置值都是在特定场景下自动触发的,不需手动调用
    • 如使用 concat 时自动调用 Symbol.isConcatSpreadable
内置值说明
Symbol.hasInstance其他对象使用 instanceof 运算符时,判断是否为该对象的实例
Symbol.isConcatSpreadable该对象用于 Array.prototype.concat() 时,是否可以展开
Symbol.unscopables使用 with 关键字时,哪些属性被 with 环境排除
Symbol.match使用 str.match(obj) 时,如果 obj 属性存在则调用,并返回该方法的返回值
Symbol.replace对象被 str.replace(obj) 调用时,返回该方法的返回值
Symbol.search对象被 str.search(obj) 调用时,返回该方法的返回值
Symbol.split对象被 str.split(obj) 调用时,返回该方法的返回值
Symbol.iterator对象进行 for...of 循环时,返回该对象的默认遍历器
Symbol.toPrimitive对象被转为原始类型值时,返回该对象对应的原始类型值
Symbol.toStringTag对象调用 toString 时,返回该方法的返回值
Symbol.species创建衍生对象时使用该属性

1.Symbol.hasInstance

  • 自定义类型检测的参数、返回结果
class Person {
  static [Symbol.hasInstance](param) {
    console.log(param); // "instanceof"关键字前面的变量
    console.log("我被用来检测类型了");
    return true; // 缺省则返回false
  }
}
let o = {};
console.log(o instanceof Person);
// {}
// 我被用来检测类型了
// true

2.Symbol.isConcatSpreadable

  • 控制当前 Symbol 值是否可以展开拼接
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
console.log(arr1.concat(arr2));
// [1, 2, 3, 4, 5, 6]

arr2[Symbol.isConcatSpreadable] = false;
console.log(arr1.concat(arr2));
// [1, 2, 3, Array(3)]
上次编辑于: