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类型 #17

Open
wozien opened this issue Oct 7, 2020 · 0 comments
Open

es6-Symbol类型 #17

wozien opened this issue Oct 7, 2020 · 0 comments
Labels

Comments

@wozien
Copy link
Owner

wozien commented Oct 7, 2020

在es5中有五种基本类型分别是字符串,数字,布尔,nullundefined,在es6中引入一种新的基本类型 Symbol,表示独一无二的值。常用于模拟创建对象的私有属性。

基本用法

调用全局函数 Symbol 创建,该函数接收一个字符串作为描述参数:

let sb = Symbol('sb');

console.log(sb); // Symbol(sb)
console.log(typeof sb); // symbol

不能使用 new 调用,因为 Symbol 是基本类型,不是返回对象。

因为 Symbol 本身表示独一无二的值,所以两个相同描述的 Symbol 是不相等的:

let sb = Symbol('sb');
let sb2 = Symbol('sb');

console.log(sb === sb2); // false

对象作为描述会先调用对象的 toString 方法:

let obj = {
  toString() {
    return 'Symbol obj';
  }
};

let sb = Symbol(obj);

console.log(sb); // Symbol(Symbol obj)

不能通过运算强制转换为字符串和数字:

let sb = Symbol('sb');
let desc = sb + ''; // Cannot convert a Symbol value to a string
let num = sb + 1; // Cannot convert a Symbol value to a number

Symbol相关方法

有时候我们需要用到同一个 Symbol 来做一些处理,就要用到 Symbol.for 方法来注册一个全局的 Symbol

let sb = Symbol.for('sb');
let sb2 = Symbol.for('sb');
let obj = {
  [sb]: '12345'
};

console.log(obj[sb]);  // 12345
console.log(sb === sb2); // true
console.log(obj[sb2]); // 12345

调用该方法会先在全局的Symbol注册表中查找有没有键为'sb'的 Symbol,如果存在则返回。不存在就先创建一个新的 Symbol ,并在全局表中注册。

Symbol.keyFor 方法返回在Symbol全局注册表中检索与该 Symbol 有关的key:

let sb = Symbol.for('sb');

console.log(Symbol.keyFor(sb)); // sb

let sb2 = Symbol('sb');

console.log(Symbol.keyFor(sb2));  // undefined

Symbol 作为对象的属性无法在 Object.keysObject.getOwnPropertyNames 方法返回,es6提供一个Object.getOwnPropertySymbols 方法来返回对象所有的 Symbol 属性。

let sb = Symbol('sb');
let obj = {
  [sb]: '12345'
};

let symbols = Object.getOwnPropertySymbols(obj);

console.log(symbols);   // [ Symbol(sb) ]
console.log(obj[symbols[0]]);  // 12345

well-know Symbol

es6提供了一些内置的 Symbol 变量,用于改变js中某些行为。比如设置构造函数的Symbol.hasInstance 可以自定义 instanceof 的行为:

function SpecialNumber() {
  //
}

Object.defineProperty(SpecialNumber, Symbol.hasInstance, {
  value: function(v) {
    return v instanceof Number && (v >= 1 && v <= 100);
  }
});

let zero = new Number(0),
  two = new Number(2);

console.log(zero instanceof SpecialNumber); // false
console.log(two instanceof SpecialNumber); // true

Symbol.toStringTag 可以改变调用 Object.prototype.toString 方法的默认行为:

function Person(name) {
  this.name = name;
}

Person.prototype[Symbol.toStringTag] = 'Person';

Person.prototype.toString = function() {
  return this.name;
};

const person = new Person('wozien');

console.log(Object.prototype.toString.call(person)); // [object Person]
console.log(person.toString());  // wozien

其他内置的Symbol及用法参考MDN文档

应用场景

作为对象的属性和方法,模拟对象的私有化:

let myKey = Symbol();
let myFunc = Symbol();
let obj = {
  [myKey]: '123',
  [myFunc]() {
    return 'bar';
  }
};
console.log(obj[myKey]);  // 123
console.log(obj[myFunc]()); // bar

定义常量,防止常量重复定义:

const COLOR_RED = Symbol('red');
const COLOR_BLUR = Symbol('blue');
const COLOR_PINK = Symbol('pink');

switch (color) {
  case COLOR_RED:
    break;
  case COLOR_BLUR:
    break;
  //
}

** 作为类型的私有属性 ** 。防止定义的冲突和外部访问:

const PASSWORD = Symbol();
class Login {
    constructor(name, password) {
        this.name = name;
        this[PASSWORD] = password;
    }
    hasPassword(pw) {
        return this[PASSWORD] === pw;
    }
}

** 自定义对象的迭代行为 ** :

let obj = {
  data: ['hello', 'world'],
  [Symbol.iterator]() {
    const self = this;
    let index = 0;
    return {
      next() {
        if (index < self.data.length) {
          return {
            value: self.data[index++]
          };
        } else {
          return { done: true };
        }
      }
    };
  }
};

for (let x of obj) {
  console.log(x);
}

// hello
// world

参考

Symbol-MDN

symbol的用法和场景

>>>原文地址

@wozien wozien added the es6 label Oct 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant