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