【Vue源碼相關】[ES6]Symbol屬性及其作用


在 symbols 誕生之前,對象的鍵只能是字符串。假如我們試着使用一個非字符串當做對象的鍵,就會被轉換為字符串,如下所示:

const obj = {};
obj.foo = 'foo';
obj['bar'] = 'bar';
obj[2] = 2;
obj[{}] = 'someobj';
console.log(obj);
// { '2': 2, foo: 'foo', bar: 'bar', '[object Object]': 'someobj' }

 

symbols 是什么?

  • symbols 是一種無法被重建的基本類型。這時 symbols 有點類似與對象創建的實例互相不相等的情況,但同時 symbols 又是一種無法被改變的基本類型數據。
const s1 = Symbol();
const s2 = Symbol();
console.log(s1 === s2); // false

當你初始化一個帶有一個接收可選字符串參數的 symbols 時,我們可以來看下,除此之外看看它會否影響自身。

const s1 = Symbol('debug');
const str = 'debug';
const s2 = Symbol('xxyy');
console.log(s1 === str); // false
console.log(s1 === s2); // false
console.log(s1); // Symbol(debug)

symbols 作為對象的屬性

  • symbols 有另一個很重要的用途,就是用作對象的 key。這兒有一個 symbols 作為對象 key 使用的例子:
const obj = {};
const sym = Symbol();
obj[sym] = 'foo';
obj.bar = 'bar';
console.log(obj); // { bar: 'bar' }
console.log(sym in obj); // true
console.log(obj[sym]); // foo
console.log(Object.keys(obj)); // ['bar']
  • 我們注意到使用 Object.keys() 並沒有返回 symbols,這是為了向后兼容性的考慮。老代碼不兼容 symbols,因此古老的 Object.keys() 不應該返回 symbols。

  • 看第一眼,我們可能會覺得 symbols 這個特性很適合作為對象的私有屬性,許多其他語言都要類似的類的隱藏屬性,這一直被認為是 JavaScript 的一大短板。不幸的是,還是有可能通過 symbols 來取到對象的值,甚至都不用試着獲取對象屬性就可以得到對象 key,例如,通過 Reflect.ownKeys() 方法就可以獲取所有的 key,包括 字符串和 symbols,如下所示:

function tryToAddPrivate(o) {
  o[Symbol('Pseudo Private')] = 42;
}
const obj = { prop: 'hello' };
tryToAddPrivate(obj);
console.log(Reflect.ownKeys(obj));// [ 'prop', Symbol(Pseudo Private) ]
console.log(obj[Reflect.ownKeys(obj)[1]]); // 42
注意:現在已經有一個旨在解決 JavaScript 私有屬性的提案,叫做 Private Fields,盡管這並不會使所有的對象受益,它仍然對對象的實例有用,Private Fields 在 Chrome 74版本可用。

阻止對象屬性名沖突

  • symbols 可能對對象的私有屬性沒有直接好處,但是它有另外一個用途,它在不知道對象原有屬性名的情況下,擴展對象屬性很有用。
  • 考慮一下當兩個不同的庫要讀取對象的一些原始屬性時,或許它們都想要類似的標識符。如果只是簡單的使用字符串 id 作為 key,這將會有很大的風險,因為它們的 key 完全有可能相同。
function lib1tag(obj) {
  obj.id = 42;
}
function lib2tag(obj) {
  obj.id = 369;
}

通過使用 symbols,不同的庫在初始化的時候生成其所需的 symbols,然后就可以在對象上任意賦值。

const library1property = Symbol('lib1');
function lib1tag(obj) {
  obj[library1property] = 42;
}
const library2property = Symbol('lib2');
function lib2tag(obj) {
  obj[library2property] = 369;
}

這方面 symbols 的確對 JavaScript 有用。然后你或許會奇怪,不同的庫進行初始化的時候為什么不使用隨機字符串,或者使用命名空間呢?

const library1property = uuid(); // random approach
function lib1tag(obj) {
  obj[library1property] = 42;
}
const library2property = 'LIB2-NAMESPACE-id'; // namespaced approach
function lib2tag(obj) {
  obj[library2property] = 369;
}
  • 你是對的,這種方法確實類似於 symbols 的這一作用,除非兩個庫使用相同的屬性名,那就會有被覆寫的風險。但是仍然有一點細微的不同,字符串是不可變的,而 symbols 可以保證永遠唯一,因此仍然有可能會有人生成重名的字符串。從數學意義上 symbols 提供了一個字符串沒有的優點。

  • 機敏的讀者已經發現這兩種方案的效果並不完全相同。我們獨有的屬性名仍然有一個缺點:它們的 key 很容易被找到,尤其是當代碼進行遞歸或者序列化對象,考慮如下的例子:

const library2property = 'LIB2-NAMESPACE-id'; // namespaced
function lib2tag(obj) {
  obj[library2property] = 369;
}
const user = {
  name: 'Thomas Hunter II',
  age: 32
};
lib2tag(user);
JSON.stringify(user);
// '{"name":"Thomas Hunter II","age":32,"LIB2-NAMESPACE-id":369}'
  • 假如我們使用 symbols 作為屬性名,json 的輸出將不會包含 symbols,這是為什么呢?因為 JavaScript 支持 symbols,並不意味着 json 規范也會跟着修改。json 只允許字符串作為 key,JavaScript 並沒有試圖讓 json 輸出 symbols。

轉自:https://blog.csdn.net/weixin_34124939/article/details/91456169


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM