ES6 Symbol

94 阅读2分钟

概述

  • 独一无二的值

  • 不能使用new命令,会报错

  • 接受一个字符串作为参数,表示对 Symbol 的描述,相同参数的Symbol函数的返回值是不相等的

let s1 = Symbol('foo');
let s2 = Symbol('bar');

s1 // Symbol(foo)
s2 // Symbol(bar)
// 没有参数的情况
let s1 = Symbol();
let s2 = Symbol();

s1 === s2 // false

// 有参数的情况
let s1 = Symbol('foo');
let s2 = Symbol('foo');

s1 === s2 // false

Symbol作为属性名

  • Symbol 值必须放在方括号之中
let mySymbol = Symbol();

// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';

// 第二种写法
let a = {
  [mySymbol]: 'Hello!'
};

// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });

// 以上写法都得到同样结果
a[mySymbol] // "Hello!"
  • 不会出现在for...infor...of循环中

  • 不会被Object.keys()Object.getOwnPropertyNames()JSON.stringify()返回

  • Object.getOwnPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名

Symbol.for

  • 重新使用同一个 Symbol 值

  • 它接受一个字符串作为参数,搜索有没有以该参数作为名称的 Symbol 值

    • 如果有,就返回这个 Symbol 值

    • 否则就新建并返回一个以该字符串为名称的 Symbol 值

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');

s1 === s2 // true

Symbol.for()Symbol()

  • 都会生成新的 Symbol

  • 前者会被登记在全局环境中供搜索,后者不会

  • Symbol.for()会先检查给定的key是否已经存在,如果不存在才会新建一个值

    • 不会每次调用就返回一个新的 Symbol 类型的值

内置Symbol

  • Symbol.hasInstance

  • Symbol.isConcatSpreadable

  • Symbol.species

  • Symbol.match

  • Symbol.replace

  • Symbol.search

  • Symbol.split

  • Symbol.toPrimitive

  • Symbol.toStringTag

  • Symbol.unscopables

  • Symbol.iterator

    • 指向该对象的默认生成遍历器的方法

实例

消除魔术字符串

  • Triangle就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护
function getArea(shape, options) {
  let area = 0

  switch (shape) {
    case 'Triangle': // 魔术字符串
      area = 0.5 * options.width * options.height
      break
    /* ... more code ... */
  }

  return area
}

getArea('Triangle', { width: 100, height: 100 }) // 魔术字符串
  • 常用的消除魔术字符串的方法,就是把它写成一个变量
const shapeType = {
  triangle: 'Triangle'
}

function getArea(shape, options) {
  let area = 0
  switch (shape) {
    case shapeType.triangle:
      area = 0.5 * options.width * options.height
      break
  }
  return area
}

getArea(shapeType.triangle, { width: 100, height: 100 })
  • 隐患
const shapeType = {
  triangle: 'Triangle',
  rectangle:'Triangle'
};
  • shapeType.triangle值不重要,只要确保不会跟其他shapeType属性的值冲突即可
const shapeType = {
  triangle: Symbol(),
  rectangle:Symbol()
}

实现私有属性

用一个字符串或者下划线的方式:不是真正的私有,依然可以遍历

var Person = (function() {
    let _name = `_name`
    // 或者 let name = 'shfjkshfkjsjkf'
    function Person(name) {
        this[_name] = name;
    }

    Person.prototype.getName = function() {
        return this[_name];
    };

    return Person;
}());

闭包:实例无法共享方法,浪费内存空间

var Person = (function() {
    function Person(name) {
        this.getName = function() {
            return name;
        };
    }

    return Person;
}());

Symbol:仍然会被Object.getOwnPropertySymbols获取到属性,进而修改该属性对应的值

var Person = (function() {
    var nameSymbol = Symbol('name');

    function Person(name) {
        this[nameSymbol] = name;
    }

    Person.prototype.getName = function() {
        return this[nameSymbol];
    };

    return Person;
}());