ES6--Symbol的學習和使用

在面試過程中,會遇到有關Symbol的問題,所以學習了下:

<script>
//=======Symbol:
        //Symbol是由ES6規範引入的一項新特性,是一種新的基礎數據類型,它的功能類似於一種標識唯一性的ID。
        //通常情況下,我們可以通過調用Symbol()函數來創建一個Symbol實例,用來表示獨一無二的值,是一種原始數據類型。
        let x = Symbol();
        console.log(typeof x);  //symbol
        // Symbol函數可以接受字符串爲參數,表示對Symbol實例的描述。爲在控制檯輸出,或者轉換爲字符串時,比較容易區分.
        let s2 = Symbol('another symbol')
        // ES2019提供了一個屬性description,直接返回Symbol的描述
        // Symbol值都是不相等的,意味着Symbol值可以作爲標識符,用於對象的屬性名,就可以保證不會出現同名的屬性
        let s3 = Symbol('another symbol')
        console.log(s3 === s2); //false
        // Symbol作爲對象的屬性名時,不能用點運算符,要使用[]
        let a = Symbol();
        let obj1 = {
            [a]: function (arg) {
                console.log(arg)
            }
        }
        obj1[a](123);  //123
        // Symbol作爲屬性名時,該屬性是公有屬性,不是私有屬性,
        
        // 使用場景:
        // 1、定義一組常量,保證常量的值都不相等.示例1:
        const log = {};
        log.levels = {
            DEBUG: Symbol('debug'),
            INFO: Symbol('info'),
            WARN: Symbol('warn')
        }
        console.log(log.levels.DEBUG, 'debug messagee'); //Symbol(debug) "debug messagee"
        console.log(log.levels.INFO, 'info messagee'); //Symbol(info) "info messagee"
        // 示例2:
        const COLOR_RED = Symbol();
        const COLOR_GREEN = Symbol();
        function getComplement(color) {
            switch (color) {
                case COLOR_RED:
                    return COLOR_RED;
                case COLOR_GREEN:
                    return COLOR_GREEN;
                default:
                    throw new ERROR('undefined color')
            }
        }
        // 常量使用symbol值最大好處,就是其他任何值都不可能有相同的值,因此可以保證上面的switch語句會按設計的方式工作。

        //2、作爲對象的key屬性,防止對象屬性被重寫,示例:
        let name = Symbol();
        {
            plugin = {};
            plugin[name] = 'plugin';
            console.log(plugin[name]); //plugin
        }
        {
            let name = Symbol();
            plugin[name] = 'user';
            console.log(plugin[name]);//user

        }
        console.log(plugin); //{Symbol(): "plugin", Symbol(): "user"}
        console.log(plugin[name]); //plugin

        // 當使用了Symbol作爲對象的屬性key後,在對該對象進行key的枚舉時,會有什麼不同?在實際應用中,我們經常會需要使用Object.keys()或者for...in來枚舉對象的屬性名,那在這方面,Symbol類型的key表現的會有什麼不同之處呢?來看以下示例代碼:
        let object1 = {
            [Symbol('name')]: '一斤代碼',
            age: 18,
            title: 'enginner'
        }
        Object.keys(object1);//["age", "title"]
        for (let p in object1) {
            console.log(p); //age title
        }
        Object.getOwnPropertyNames(object1);//["age", "title"]
        // 從以上代碼的輸出,不難看出,Symbol類型的key是不能通過Object.keys()或者for...in來枚舉,它未被包含在對象自身的屬性名集合(property names)之中。所以,利用該屬性,我們可以把一些不需要對外操作和訪問的屬性使用Symbol來定義。
        // 當使用JSON.stringify(),將對象轉換爲JSON字符串時,Symbol也被排除在外,即不含Symbol的值。
        console.log(JSON.stringify(object1)); //{"age":18,"title":"enginner"} 
        
        // 那麼,怎麼獲取以Symbol方式定義的對象屬性呢?可以使用下列針對Symbol的API:
        // => 使用Object的API:
        Object.getOwnPropertySymbols(object1); //[Symbol(name)]
        // => 使用新增的反射API
        Reflect.ownKeys(object1); //(3) ["age", "title", Symbol(name)]

        // 3、使用Symbol定義類的私有屬性/方法
        // 模塊化中的使用,在a.js文件中:
        const PASSWORD = Symbol();
        class Login {
            constructor(username, password) {
                this.username = username;
                this[PASSWORD] = password;
            }
            checkPassword(pwd) {
                return this[PASSWORD] === pwd
            }
        }
        export default Login;

        // b.js文件:
        import Login from './a.js';
        const login = new Login('admin', '123455');
        login.checkPassword('123456');
        login.PASSWORD // oh!no! 
        login[PASSWORD];// oh!no!
        login['PASSWORD']// oh!no!

        // 由於Symbol常量被定義在a.js模塊中,在b。js中拿不到,也不能創建一個一模一樣的(是唯一的),所以這個PASSWORD是限制在a.js中。所以使用它來定義的類屬性是沒有辦法被模塊外訪問到的,達到了一個私有化的效果。
        // 註冊和獲取全局Symbol
        //通常情況下,在瀏覽器窗口(window)中,使用Symbol()函數來定義和Symbol實例就夠了,但,如果應用設計到多個window(如使用iframe),並需要這些window中創建的Symbol是同一個,就不能使用Symbol()函數了。要使用另一個API:就是Symbol.for()
        //可以註冊或獲取一個window間全局的Symbol實例
        let gs1 = Symbol.for('global_symbol_1');  //註冊一個全局Symbol
        let gs2 = Symbol.for('global_symbol_1');
        //獲取全局Symbol
        console.log(gs1 === gs2); //true 

</script>      

參考:https://www.jianshu.com/p/f40a77bbd74e

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章