导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

⭐️ 类型与作用

Symbol(); // 不是构造函数,不可用new Symbol()

var s1 = Symbol();
var s2 = Symbol();
console.log(s1 === s2); // false
console.log(s1, '--', s2);
console.log(typeof s1);

Untitled

var s1 = Symbol();
s1.a = 1; // 无法添加属性
console.log(s1.a);

Untitled

通过传入的字符串添加不同的标识符

var s1 = Symbol('ss');
var s2 = Symbol({a: 1}); // 会调用Object.prototype.toString()
var s3 = Symbol(undefined);
var s4 = Symbol(null);
console.log(s1);
console.log(s2);
console.log(s3);
console.log(s4);

Untitled

symbol 类型数据无法使用 Number 包装类进行数据转换,String 和 Boolean 可以

var s1 = Symbol(1);
console.log(s1);
console.log(String(s1));
console.log(Boolean(s1));
console.log(Number(s1));

Untitled

var s1 = Symbol(null);
console.log(Object.getPrototypeOf(s1));

Untitled

toString

var s1 = Symbol()
console.log(s1.toString());
console.log(!s1)

Untitled

使用

var name1 = Symbol();
var obj = {};
obj[name1] = 'zhangsan';
console.log(obj);

Untitled

var name1 = Symbol();
var eat = Symbol();
var person = {
	[name1]: 'zhangsan',
  [eat](){
  	console.log(this[name1]);
  }
}
person[eat]();

Untitled

⭐️ Symbol.hasInstance

function Foo() {}
var foo = new Foo();
console.log(Foo[Symbol.hasInstance](foo))
// 相当于 foo instanceof Foo

Untitled

Symbol.hasInstance 用于判断某对象是否为某构造器的实例。因此你可以用它自定义 instanceof 操作符在某个类上的行为。

class Array1 {
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance);
  }
}

console.log([] instanceof Array1);
// expected output: true

Symbol.for()

var s1 = Symbol.for('foo');
var s2 = Symbol.for('foo');
console.log(s1 === s2);

Untitled

Symbol.keyFor() 获取标识符

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

console.log(Symbol.keyFor(s1));

Untitled

遍历

for in 循环无法遍历 Symbol 类型的属性

var obj = {}
var a = Symbol('a');
var b = Symbol('b');
obj[a] = 'hello';
obj[b] = 'world';
obj.c = '!!!!';
for(let i in obj){
	console.log(i);
}

Untitled

for-of 无法遍历对象(报错)

var obj = {}
var a = Symbol('a');
var b = Symbol('b');
obj[a] = 'hello';
obj[b] = 'world';
obj.c = '!!!!';
for(let i of obj){
	console.log(i);
}

Untitled

assign 合并对象

var obj = {}
var a = Symbol('a');
var b = Symbol('b');
obj[a] = 'hello';
obj[b] = 'world';
obj.c = '!!!!';
var obj1 = {};
Object.assign(obj1, obj);
console.log(obj1);

Untitled

Object.getOwnPropertySymbols() 只会遍历 symbol 类型的属性

var obj = {}
var a = Symbol('a');
var b = Symbol('b');
obj[a] = 'hello';
obj[b] = 'world';
obj.c = '!!!!';
const objSymbols = Object.getOwnPropertySymbols(obj);
console.log(objSymbols);

Untitled

const obj = {c:1, d:2};
let a = Symbol('a');
let b = Symbol('b');
let _a = Symbol('_a');
let _b = Symbol('_b');
obj[a] = 'hello';
obj[b] = 'world';
Object.defineProperties(obj,{
    e:{
        value: 5,
        enumerable: true
    },
    f:{
        value: 6,
        enumerable: false
    },
    [_a]:{
        value: -1,
        enumerable: true
    },
    [_b]:{
        value: -2,
        enumerable: false
    },
})
let h = Symbol('h');
let i = Symbol('i');
let j = Symbol('j');
const obj1 = {
    g: 7,
    [h]: 8
}
Object.defineProperties(obj1,{
    [i]:{
        value: 9,
        enumerable: true
    },
    [j]:{
        value: 10
    },
    k:{
        value: 11
    }
})
Object.setPrototypeOf(obj, obj1)

// for in 遍历自身和继承的可枚举属性,不包含symbol类型的值
for(let i in obj){
	console.log(i);
}

// Object.keys() 遍历自身可枚举的,不包含symbol类型的值
console.log(Object.keys(obj));

// Object.getOwnPropertySymbols() 遍历自身symbol类型的值
Object.getOwnPropertySymbols(obj)

// 遍历自身可枚举的,包含symbol类型的值
var obj3 = {}
Object.assign(obj3, obj);

JSON.stringify()//遍历自身可枚举的

⭐️ 应用场景

应用场景1:使用 Symbol 来作为对象属性名

平常我们对象的属性都是字符串

const obj = {
  name: 'Sunshine_Lin',
  age: 23
}
console.log(obj['name']) // 'Sunshine_Lin'
console.log(obj['age']) // 23

其实也可以用Symbol来当做属性名

const gender = Symbol('gender')
const obj = {
  name: 'Sunshine_Lin',
  age: 23,
  [gender]: '男'
}
console.log(obj['name']) // 'Sunshine_Lin'
console.log(obj['age']) // 23
console.log(obj[gender]) // 男

但是Symbol作为属性的属性不会被枚举出来,这也是 JSON.stringfy(obj) 时,Symbol 属性会被排除在外的原因

console.log(Object.keys(obj)) // [ 'name', 'age' ]
for(const key in obj) {
  console.log(key) // name age
}
console.log(JSON.stringify(obj)) // {"name":"Sunshine_Lin","age":23}

其实想获取Symbol属性也不是没办法。

// 方法一
console.log(Object.getOwnPropertySymbols(obj)) // [ Symbol(gender) ]
// 方法二
console.log(Reflect.ownKeys(obj)) // [ 'name', 'age', Symbol(gender) ]

应用场景2:使用 Symbol 来替代常量

有以下场景

// 赋值
const one = 'oneXin'
const two = 'twoXin'

function fun(key) {
  switch (key) {
    case one:
        return 'one'
      break;
    case two:
        return 'two'
      break;
  }
}

如果变量少的话还好,但是变量多的时候,赋值命名很烦,可以利用 Symbol 的唯一性

const one = Symbol()
const two = Symbol()

应用场景3:使用 Symbol 定义类的私有属性

以下例子,PASSWORD 属性无法在实例里获取到

class Login {
  constructor(username, password) {
    const PASSWORD = Symbol()
    this.username = username
    this[PASSWORD] = password
  }
  checkPassword(pwd) { return this[PASSWORD] === pwd }
}

const login = new Login('123456', 'hahah')

console.log(login.PASSWORD) // 报错
console.log(login[PASSWORD]) // 报错
console.log(login[PASSWORD]) // 报错