美文网首页
symbol 的理解和使用

symbol 的理解和使用

作者: 达文西_Huong | 来源:发表于2020-06-17 10:55 被阅读0次

    理解和使用ES6中的 Symbol

    原文:https://www.jianshu.com/p/f40a77bbd74e


    ES6中引入了一种新的基础数据类型symbol,但是一直以来都没什么机会了解,今天看了一篇文章里面偶然提到,然后发现自己不懂,于是就去百度了一波。然后就发现了这么一篇精品。为了加深自己的理解,于是转载过来。同时也方便自己以后复习用。

    如果转载的不好,还请移步到原文。

    这是一种新的基础数据类型 (primitive type)

    symbol 是由ES6 规范引入的一项新特性,它的功能类似于一种唯一标识的id。我们一般直接调用symbol()来创建一个symbol实例。

        let s1 = Symbol()
    

    或者你也可以在调用Symbol()的时候,传入一端字符串。该字符串相当于Symbol实例的描述

        let s2 = Symbol('another symbol')
    

    由于symbol是一种基础的数据类型,所以当我们用typeof 查看的时候 返回的是 symbol

        typeof s1 // 'symbol'
    

    同时symbol 的实例时唯一的,所以,当你比较两个symbol的时候,总会返回false

        let s1 = Symbol()
        let s2 = Symbol('another symbol')
        let s3 = Symbol('another symbol')
    
        s1 === s2 // false
        s2 === s3 // false
    

    应用场景1 -- 使用symbol来作为对象属性名(key)

    在以前,我们定义一个对象的属性的时候

        let obj {
            abc:123,
            "hello":"world"
        }
    
        obj['abc']   // 123
        obj['hello'] // world
    

    而现在,使用symbol可以同样定义对象的属性

        const PROP_NAME = Symbol()
        const PROP_AGE  = Symbol()
    
        let obj = {
            [PROP_NAME]:"huong"
        }
        obj[PROP_AGE] = 18
    
        obj[PROP_NAME] // "huong"
        obj[PROP_AGE]  // 18
    

    关于对象的枚举。如果使用了Symbol定义的属性,在使用传统的for..inObject.keys()是不能枚举到的。

        let obj = {
            [Symbol('name')]:"huong",
            age: 18,
            title:'Engineer'
        }
        Object.keys(obj) // ['age','title']
    
        for(let p in obj){
            console.log(p)  // age title
        }
    
        Object.getOwnPropertyNames(obj)  // ['age','title']
    

    由上代码可知,Symbol类型的key是不能通过传统方式去枚举出来的。因为它并未被包含在自身的属性名合集中(property names)。所以利用该特性,我们可以把一些不需要对外操作和访问的属性使用Symbol来定义。

    同样,使用JSON.stringify()将对象转成字符串时候,Symbol属性也会被排除在输出内容之外

        JSON.stringify(obj)  // {"age":18 , "title":"Engineer" }
    

    我们可以利用这一特点来更好的设计我们的数据对象,让"对内操作" 和 "对外选择性输出" 变得更加优雅

    然而这样的话,我们就没办法获取以Symbol方式定义的对象属性了么。也不是,还是有一些专门针对Symbol的API滴

        // 使用Object的API
        Object.getOwnPropertySymbols(obj)  // [Symbol(name)]
    
        // 使用新增的反射API
        Reflect.ownKeys(obj)  // [Symbol(name), 'age', 'tile' ]
    

    应用场景2 使用Symbol来替代常量

    先来看看下面的代码

        const TYPE_AUDIO = 'AUDIO'
        const TYPE_VIDEO = 'VIDEO'
        const TYPE_IMAGE = 'IMAGE'
    
        function handleFileResource(resource) {
            switch(resource.type) {
                case TYPE_AUDIO:
                    playAudio(resource)
                    break
                case TYPE_VIDEO:
                    playVideo(resource)
                    break
                case TYPE_IMAGE:
                    previewImage(resource)
                    break
                default:
                    throw new Error('Unknown type of resource')
            }
        }
    

    现在有了Symbol 我们可以改成这样

        const TYPE_AUDIO = Symbol()
        const TYPE_VIDEO = Symbol()
        const TYPE_IMAGE = Symbol()
    
        function handleFileResource(resource) {
            switch (resource) {
                case TYPE_AUDIO:
                    console.log('TYPE_AUDIO')
                    break
                case TYPE_VIDEO:
                    console.log('TYPE_VIDEO')
                    break
                case TYPE_IMAGE:
                    console.log('TYPE_IMAGE')
                    break
                default:
                    throw new Error('Unknown type of resource')
            }
        }
    
        // 当你想要判断的时候只需要把值传进去
        handleFileResource(TYPE_VIDEO)      // TYPE_AUDIO
    

    应用场景3 使用Symbol定义类的私有属性/方法

    使用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'
    
        const login = new Login('admin', '123456')
    
        login.checkPassword('123456')   // true
    
        login.PASSWORD      // oh!no!
        login[PASSWORD]     // oh!no!
        login['PASSWORD']   // oh!no!
    
    

    由于Symbol常量被定义在a.js中,外面的模块是访问不了这个Symbol的。因此可以达成一个私有变量。

    注册和获取全局Symbol

    通常情况下,我们在一个浏览器窗口中(window),使用Symbol() 函数来定义和Symbol实例就足够了。但是如果你想你想多个window中使用某些Symbol是同一个。那就不能使用Symbol()函数。需要用到另一个API去定义Symbol.for()它可以注册或获取一个window间全局的Symbol实例

        let gs1 = Symbol.for('golbal_symbol_1') // 注册一个全局Symbol
        let gs2 = Symbol.for('global_symbol_1') // 获取全局的Symbol
        
        gs1 === gs2   // true
    

    这样一个Symbol不光在单个window中是唯一的,在多个相关window间也是唯一的了。

    以上

    相关文章

      网友评论

          本文标题:symbol 的理解和使用

          本文链接:https://www.haomeiwen.com/subject/ivpatktx.html