Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES6之Symbol #15

Open
mhfe123 opened this issue Dec 15, 2018 · 0 comments
Open

ES6之Symbol #15

mhfe123 opened this issue Dec 15, 2018 · 0 comments

Comments

@mhfe123
Copy link
Contributor

mhfe123 commented Dec 15, 2018

Symbol出现的背景及简介

ES6里边出现了一个新的数据类型,我们的js不在单单是Array,Object,Function,Number,String,undefined,null,Boolean这几种数据类型,还多了Symbol数据类型。那么它是为什么出现的呢?

ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol的原因。

Symbol 值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

Symbol基本使用

// symbol 基本用法
let obj1 = {a: 1};
let obj2 = {toString: 1};
let obj3 = {
  toString() {
    return 'abc';
  }
}
let symbol1 = Symbol(); // Symbol()
typeof symbol1; // symbol
let symbol2 = Symbol('string'); // Symbol('string')
let symbol3 = Symbol(1); // Symbol(1)
let symbol4 = Symbol(obj1); // Symbol([object Object])
obj1.toString(); // [object Object]
// let symbol5 = Symbol(obj2); // symbol.html:20 Uncaught TypeError: Cannot convert object to primitive valueat Symbol (<anonymous>)
let symbol6 = Symbol(obj3); // Symbol(abc)
let symbol7 = Symbol(true); // Symbol(true)
let symbol8 = Symbol(undefined); // Symbol()
let symbol9 = Symbol(null); // Symbol(null)
let symbol10 = Symbol(function(){return 'hello'}); // Symbol(function(){return 'hello'})

symbol值是通过Symbol函数生成的,所以我们定义的时候都是var v = Symbol()这种形式,通过上面的输出我们可以看到symbol函数里的参数会调用参数自己的toString方法,传入对象的话就会变成[Object Object]这种形式,如果传入的参数toString方法被改写不在是一个function,那么就会报错。

Symbol唯一性的校验

// 唯一性
let s1 = Symbol('foo');
let s2 = Symbol('foo');
console.log(s1 === s2); // false
console.log(s1 === s1); // true

let o1 = {};
let o2 = {};
o1[s1] = s1;
o2[s1] = s2;
o2[s2] = s2;

console.log(o2); // {Symbol(foo): Symbol(foo), Symbol(foo): Symbol(foo)}
console.log(o1[s1] === o2[s2]); // false
console.log(o1[s1] === o2[s1]); // false
// o2[s1] = s1;
// console.log(o1[s1] === o2[s1]); // true
console.log(o2[s1] === o2[s2]); // true
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');
    }
}
console.log(getComplement(COLOR_RED)); // Symbol()
console.log(getComplement(COLOR_GREEN)); // Symbol()

通过上面几个console我们可以看出symbol的值只能等于它自身,即使是写法一样都是Symbol()但是通过不同的变量去保存得到的值也是不相等的,这就是symbol的唯一性

关于遍历

Symbol 作为属性名,该属性不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。

但是,它也不是私有属性,有一个Object.getOwnPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名。Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

// 遍历
let for1 = Symbol();
let for2 = Symbol();
let for3 = Symbol();
let tmpObj = {
  [for1]: '1',
  [for2]: '1',
  [for3]: '1',
  name: 'haha'
}
console.log(tmpObj);
// {name: "haha", Symbol(): "1", Symbol(): "1", Symbol(): "1"}
for (let key in tmpObj) {
  console.log(key); // name key
}
let tmp1 = Object.keys(tmpObj); // ["name"] 
let tmp2 = Object.getOwnPropertyNames(tmpObj); // ["name"] 
let tmp3 = JSON.stringify(tmpObj); // {"name":"haha"}
let tmp4 = Object.getOwnPropertySymbols(tmpObj); // [Symbol(), Symbol(), Symbol()] 
let tmp5 = Reflect.ownKeys(tmpObj); // ["name", Symbol(), Symbol(), Symbol()]

Symbol.for(),Symbol.keyFor()

Symbol.for()与Symbol()这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。比如,如果你调用Symbol.for("cat")30 次,每次都会返回同一个 Symbol 值,但是调用Symbol("cat")30 次,会返回 30 个不同的 Symbol 值。

Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key。

// 获取同一个symbol值
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');

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

Symbol("bar") === Symbol("bar")
// false
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"

let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant