关于javascript:ES6高级特性Symbol

34次阅读

共计 3790 个字符,预计需要花费 10 分钟才能阅读完成。

Symbol

ES6 引入了一种新的原始数据类型 Symbol,示意举世无双的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)

# 简略应用
let s = Symbol();
typeof s
// "symbol"

# 承受字符串作为参数
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"
String(s1)

# 能够应用 toString() 办法
const obj = {toString() {return 'abc';}
};
const sym = Symbol(obj);
sym // Symbol(abc)

# 雷同的参数值是不相等的
// 没有参数的状况
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有参数的状况
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false

# 无奈参加运算
let sym = Symbol('My symbol');
"your symbol is" + sym
// TypeError: can't convert symbol to string
`your symbol is ${sym}`
// TypeError: can't convert symbol to string

# Symbol 值能够显式转为字符串、布尔值、然而不能转为数字
let sym = Symbol('My symbol');
String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'

let sym = Symbol();
Boolean(sym) // true
!sym  // false
if (sym) {// ...}
Number(sym) // TypeError
sym + 2 // TypeError

# 作为属性名的 symbol
let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
let a = {[mySymbol]: 'Hello!'
};
// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!'});
// 以上写法都失去同样后果
a[mySymbol] // "Hello!"
# 留神,Symbol 值作为对象属性名时,不能用点运算符。const mySymbol = Symbol();
const a = {};
a.mySymbol = 'Hello!';
a[mySymbol] // undefined
a['mySymbol'] // "Hello!"

let s = Symbol();
let obj = {[s]: function (arg) {...}
};

obj[s](123);
// ==> 应用对象加强法更简洁的写法:let obj = {[s](arg) {...}
};

Symbol 利用场景

# 场景一:常量定义
const log = {};
log.levels = {DEBUG: Symbol('debug'),
  INFO: Symbol('info'),
  WARN: Symbol('warn')
};
console.log(log.levels.DEBUG, 'debug message');
console.log(log.levels.INFO, 'info message');

// 定义常量 场景 2
const COLOR_RED    = Symbol();
const COLOR_GREEN  = Symbol();
function getComplement(color) {switch (color) {
    case COLOR_RED:
      return COLOR_GREEN;
    case COLOR_GREEN:
      return COLOR_RED;
    default:
      throw new Error('Undefined color');
    }
}


# 场景二:打消魔术字符串
const shapeType = {triangle: 'Triangle'};

function getArea(shape, options) {
  let area = 0;
  switch (shape) {
    case shapeType.triangle:
      area = .5 * options.width * options.height;
      break;
  }
  return area;
}
getArea(shapeType.triangle, { width: 100, height: 100});
// 应用 symbol 替换如下:const shapeType = {triangle: Symbol()
};

# 场景 3:

Symbol 的非凡注意事项

# 属性名的遍历
/**
Symbol 作为属性名,遍历对象的时候,该属性不会呈现在 for...in、for...of 循环中,也不会被 Object.keys()、Object.getOwnPropertyNames()、JSON.stringify() 返回。然而,它也不是公有属性,有一个 Object.getOwnPropertySymbols() 办法,能够获取指定对象的所有 Symbol 属性名。该办法返回一个数组,成员是以后对象的所有用作属性名的 Symbol 值。**/
const obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
const objectSymbols = Object.getOwnPropertySymbols(obj);
objectSymbols
// [Symbol(a), Symbol(b)]

// 用例 2
const obj = {};
const foo = Symbol('foo');
obj[foo] = 'bar';
for (let i in obj) {console.log(i); // 无输入
}
Object.getOwnPropertyNames(obj) // []
Object.getOwnPropertySymbols(obj) // [Symbol(foo)]

// 新的 API,Reflect.ownKeys() 办法能够返回所有类型的键名,包含惯例键名和 Symbol 键名。let obj = {[Symbol('my_key')]: 1,
  enum: 2,
  nonEnum: 3
};
Reflect.ownKeys(obj)
//  ["enum", "nonEnum", Symbol(my_key)]
// Symbol 值作为键名,不会被惯例办法遍历失去。咱们能够利用这个个性,为对象定义一些非公有的、但又心愿只用于外部的办法。let size = Symbol('size');
class Collection {constructor() {this[size] = 0;
  }
  add(item) {this[this[size]] = item;
    this[size]++;
  }
  static sizeOf(instance) {return instance[size];
  }
}
let x = new Collection();
Collection.sizeOf(x) // 0
x.add('foo');
Collection.sizeOf(x) // 1
Object.keys(x) // ['0']
Object.getOwnPropertyNames(x) // ['0']
Object.getOwnPropertySymbols(x) // [Symbol(size)]
// 以上这段代码,对象 x 的 size 属性是一个 Symbol 值,所以 Object.keys(x)、Object.getOwnPropertyNames(x) 都无奈获取它。这就造成了一种非公有的外部办法的成果。

Symbol.for(),Symbol.keyFor()

# 有时,咱们心愿从新应用同一个 Symbol 值 Symbol.for()
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
// 问题:Symbol.for() 与 Symbol() 有啥区别?// 前者会被注销在全局环境中供搜寻,后者不会。Symbol.for("bar") === Symbol.for("bar")
Symbol("bar") === Symbol("bar")

# Symbol.keyFor() 办法返回一个已登记的 Symbol 类型值的 key。let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined

// I*Symbol.for() 为 Symbol 值注销的名字,是全局环境的,不论有没有在全局环境运行。function foo() {return Symbol.for('bar');
}
const x = foo();
const y = Symbol.for('bar');
console.log(x === y); // true

正文完
 0