重溫 ES6 Symbol
1.Symbol 通過工廠函式建立,不能以 new 的方式建立,所以使用 instanceof 運算子返回的結果為 false
var sym = Symbol(); var sym1 = new Symbol(); // TypeError sym instanceof Symbol // false
2.Symbol 使用 typeof 運算子返回 “symbol”
var sym = Symbol('foo'); typeof sym;// "symbol"
3.Symbol 工廠函式能支援一個可選的引數,用於描述當前的 symbol
var sym2 = Symbol('foo'); var sym3 = Symbol('foo');
4.Symbol 是唯一的,Symbol("foo") == Symbol("foo")
返回 false
Symbol('foo') === Symbol('foo'); // false
5.Symbol 與數值或字串進行運算時,會丟擲異常
sym | 0 // TypeError Symbol("foo") + "bar" // TypeError
6.Symbol 工廠函式返回的 symbol,可作為物件的屬性名,可以避免屬性衝突,在for...in
迭代中不可列舉
var obj = {}; obj[Symbol("a")] = "a"; obj[Symbol.for("b")] = "b"; obj["c"] = "c"; obj.d = "d"; for (var i in obj) { console.log(i); // logs "c" and "d" }
7.Symbol 工廠函式返回的值,可作為物件屬性名,當使用JSON.stringify()
進行序列化時,該屬性會被忽略
JSON.stringify({[Symbol("foo")]: "foo"});// '{}'
8.Symbol 是唯一的,但可以使用 Symbol.for() 共享同一個 Symbol 值
var mySymbol1 = Symbol.for('some key'); var mySymbol2 = Symbol.for('some key'); mySymbol1 == mySymbol2 //true
Symbol 實戰
物件字面量私有屬性和方法
const myPrivateMethod = Symbol("myPrivateMethod"); const myPrivateProperty = Symbol("myPrivateProperty"); const obj = { [myPrivateProperty]: "semlinker", [myPrivateMethod]() { return `Hello ${this[myPrivateProperty]}!!!`; }, hello() { console.log(this[myPrivateMethod]()); } }; console.log(Object.keys(obj)); console.log(obj.hello());
除了在建立物件字面量時可以使用 Symbol 外,在定義類的私有屬性和方法時也可以使用。
類的私有屬性和方法
const myPrivateMethod = Symbol("myPrivateMethod"); const myPrivateProperty = Symbol("myPrivateProperty"); class MyClass { constructor() { this[myPrivateProperty] = "semlinker"; } [myPrivateMethod]() { return `Hello ${this[myPrivateProperty]}!!!`; } hello() { console.log(this[myPrivateMethod]()); } } const myCls = new MyClass(); console.log(myCls.hello());
在 ES6 中,引入了一些全域性的 Symbols,比如:Symbol.match,Symbol.replace,Symbol.search,Symbol.iterator 和 Symbol.split。這裡我們簡單介紹一下 Symbol.search 和 Symbol.iterator。
Symbol.iterator
class Skill { constructor() { this.skills = ['Angular', 'React', 'Vue', 'Koa', 'Ionic']; } [Symbol.iterator]() { let index = 0; return { next: () => { const value = this.skills[index++]; const done = index === this.skills.length + 1; return { value, done }; } } } } const mySkills = new Skill(); console.log([...mySkills]); for (let skill of mySkills) { console.log(`My skill is ${skill}`); }
Symbol.search
先來簡單看個示例:
'angular'.search('ng') // 4
該示例的執行流程:
-
解析
'angular'.search('ng')
-
把 ‘angular’ 轉換為字串物件
new String('angular')
-
把 ‘ng’ 轉換為正則物件
new Regexp('ng')
-
呼叫 ‘angular’ 字串物件的
search
方法,該方法內部會自動呼叫ng
正則物件的Symbol.search
方法
具體可以參考以下虛擬碼:
// pseudo code for String class class String { constructor(value) { this.value = value; } search(obj) { obj[Symbol.search](this.value); } } class RegExp { constructor(value) { this.value = value; } [Symbol.search](string) { return string.indexOf(this.value); } }
此外利用 Symbol.search 我們還可以讓String.prototype.search()
方法呼叫我們自定義物件內部的Symbol.search()
方法,從而實現自定義 search 邏輯:
class Article { constructor(tag) { this.tag = tag; } [Symbol.search](string) { return string.indexOf(this.tag) >= 0 ? 'Found' : 'Not_Found'; } } var article = new Article('Angular'); console.log('Angular7'.search(article)); // Found console.log('重溫ES6'.search(article)); // Not_Found
以上示例的執行流程:
-
解析
'Angular7'.search(article)
語句 -
把 ‘Angular7’ 轉換為字串物件
new String("Angular7")
- 由於 article 是物件,這裡不需要進行轉換
-
呼叫 ‘Angular7’ 字串物件的
search
方法,該方法會自動呼叫article
物件內部的Symbol.search
方法,比如article[Symbol.search]('Angular7')
本文簡單介紹了 ES6 Symbol 的一些特性,然後介紹了 Symbol 幾個應用場景,若想進一步瞭解 Symbol,可以閱讀一下ofollow,noindex">冴羽 大神寫的ES6 系列之模擬實現 Symbol 型別 這一篇文章。