symbol


ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。

声明定义symbol的几种方式

// 第一种定义方式
let s = Symbol(); console.log(typeof s); // symbol

由于symbol的值是独一无二的,因此根据此特性,两个变量即使值是一样的,也不相等。

let s1 = Symbol();
let s2 = Symbol();
console.log(s1 === s2); // false
// 注意,Symbol函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。
let s = Symbol('hello');
let s1 = Symbol('hello');
console.log(s === s1); // false

给symbol添加参数以后,就等于为它们加上了描述,输出的时候就能够分清,到底是哪一个值。

注意:Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。

 

// 第二种定义方式(登记机制)
let cms = Symbol.for();
console.log(cms); // Symbol(undefined)

let cms1 = Symbol.for("symbol");
console.log(cms1); // Symbol(symbol)

let cms2 = Symbol.for("symbol");
console.log(cms1 === cms2); //true

 

Symbol.for()Symbol()这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()每次调用,返回同一个Symbol值。但是Symbol每次调用会返回不同的值。

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

 

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

let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined

 

上面代码中,变量s2属于未登记的 Symbol 值,所以返回undefined

ymbol.prototype.description

ES2019 提供了一个实例属性description,直接返回 Symbol 的描述。

let s = Symbol("hello world");
// ES2019
console.log(s.description); // hello word

作为属性名的 Symbol

由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。

let mySymbol = Symbol();
let a = {}
// 写法1:
a[mySymbol] = "hello";

// 写法2
let a1 = {
    [mySymbol]: "hello"
}

console.log(a[mySymbol]); // hello
console.log(a1[mySymbol]); // hello

注意,Symbol 值作为对象属性名时,不能用点运算符。

const mySymbol = Symbol();
const a = {};

a.mySymbol = 'Hello!';
a[mySymbol] // undefined
a['mySymbol'] // "Hello!"

上面代码中,因为点运算符后面总是字符串,所以不会读取mySymbol作为标识名所指代的那个值,导致a的属性名实际上是一个字符串,而不是一个 Symbol 值。

同理,在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。

let s = Symbol();

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

obj[s](123);

采用增强的对象写法,上面代码的obj对象可以写得更简洁一些。

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

属性名的遍历 

Symbol 作为属性名,遍历对象的时候,该属性不会出现在for...infor...of循环中,也不会被Object.keys()Object.getOwnPropertyNames()JSON.stringify()返回。

let a = Symbol("foo");
let b = Symbol("baz");
let obj = {
    c: "jacascript",
    d: "vue"
}
// 写法1:
obj[a] = "html";
obj[b] = "css";

for (let item in obj) {
    console.log(obj[item]); 
}
// jacascript 
// vue

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

let a = Symbol("foo");
let b = Symbol("baz");
let obj = {
    c: "jacascript",
    d: "vue"
}
// 写法1:
obj[a] = "html";
obj[b] = "css";

for (let item in obj) {
    console.log(obj[item]); // jacascript vue
}

const mySymbol = Object.getOwnPropertySymbols(obj);
console.log(mySymbol); // [ Symbol(foo), Symbol(baz) ]

另一个新的 API,Reflect.ownKeys()方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。

let a = Symbol("foo");
let b = Symbol("baz");
let obj = {
    c: "jacascript",
    d: "vue"
}
// 写法1:
obj[a] = "html";
obj[b] = "css";

for (let item in obj) {
    console.log(obj[item]); // jacascript vue
}

const mySymbol = Object.getOwnPropertySymbols(obj);
console.log(mySymbol);  // [ Symbol(foo), Symbol(baz) ]

const mySymbol1 = Reflect.ownKeys(obj);
console.log(mySymbol1); // [ 'c', 'd', Symbol(foo), Symbol(baz) ]

上面代码,对象obj上定义了2个属性c、然后添加了2个Symbol属性。循环遍历的时候只打印了自己的属性。通过Object.getOwnPropertySymbols()方法返回得到所有的Symbol属性的数组。

通过Reflect.ownKeys();方法返回全部属性数组。

使用symbol解决字符串耦合的问题

例如:打印一个对象中两个同名人的分数

let user1 = "李四";
let user2 = "李四";
let grade = {
    [user1]: {
        js: 100,
        css: 89,
        html: 50
    },
    [user2]: {
        js: 90,
        css: 99,
        html: 70
    },
}
console.log(grade); // 李四: {js: 90, css: 99, html: 70}
 

上面代码,打印后我们会发现,前者会被后者覆盖掉。因为对象中两个key是耦合的。

解决方案:定义成Symbol方式

let user1 = {
    name: "李四",
    key: Symbol()
};
let user2 = {
    name: "李四",
    key: Symbol()
};
let grade = {
    [user1.key]: {
        js: 100,
        css: 89,
        html: 50
    },
    [user2.key]: {
        js: 90,
        css: 99,
        html: 70
    },
}
console.log(grade[user1.key]); // { js: 100, css: 89, html: 50 }
console.log(grade[user2.key]); // { js: 90, css: 99, html: 70 }

注意:存取值的时候,需采用对象[]的方式把变量放入中括号中。否则会当成字符串。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM