美文网首页
JavaScript之Symbol

JavaScript之Symbol

作者: 又菜又爱分享的小肖 | 来源:发表于2021-06-28 22:05 被阅读0次

    前面说过,ES5中的对象属性名都是字符串,容易造成属性之间的冲突。比如我们在使用一个别人提供的对象,但是我想给这个对象添加自己想要的方法,这个方法的名字可能与现有的方法名字产生冲突,从而会覆盖原有的方法&属性值。如果有一种方式,可以保证每个属性都是独一无二的就好了,这样就能解决属性冲突的问题。这也是ES6推出类型Symbol的原因。

    JavaScript在ES5有5种基本数据类型,分别是:Null,Undefined,String,Boolean,Number,ES6新增了一个基本数据类型Symbol,表示独一无二的值。

            let s = Symbol();
            console.log(typeof s); // "Symbol";
    

    Symbol函数前不能使用new命令,否则会报错。因为生成Symbol是一个基本数据类型,不是对象。也可以这样说,因为不是对象,所以不能给该值添加属性。

    如果Symbol的参数是一个对象,就会调用该对象toString方法,将其转为字符串,然后才生成一个Symbol值。

            const obj = {
                toString() {
                    return "1"
                }
            }
            const sym = Symbol(obj);
            console.log(sym); // Symbol(1)
    

    上面说过Symbol类型是一个独一无二的值。那就说明Symbol类型不等于自己本身。
    无论是没有参数还是加了参数,都不等于自己相同的值。

    console.log(Symbol() === Symbol()); //false
    

    Symbol值不能与其他类型的值进行运算,否则会报错。
    Symbol值可以转为布尔值,但是不能转为数值。

    写法

            var mysymbol = Symbol();
            var a = new Object();
            a.[mysymbol] = '1';
    
            var mysymbol = Symbol();
            var a = {
                [mysymbol]: '2' 
            }
    
            var mysymbol = Symbol();
            var a = {};
            Object.defineProperty(a, mysymbol, {
                value: '3'
            })
    

    不能使用点运算符,因为点运算符后面总是字符串,所以不会读取mysymbol作为标识名所指代的值,导致a的属性名实际上是一个字符串,而不是一个symbol值。

    消除魔法字符串

    魔术字符串指的是,在代码之中多次出现,与代码形成强耦合的某一个具体的字符串或数值。风格良好的代码,应该尽量消除魔术字符串,而由含义清晰的变量代替。

            function getArea(shape, options){
                var area = 0;
                switch (shape) {
                    case 'Triangle': //魔术字符串
                    area = .5 * options.width * options.height;
                    break;  
                }
                return area;
            }
           console.log(getArea('Triangle', {width: 100, height: 100})) ;
    

    常用的消除魔术字符串的方法,就是把它写成一个变量。

            var shapeType = {
                shape: 'Triangle'
            }
            function getArea(shape, options){
                var area = 0;
                switch (shape) {
                    case shapeType.shape ://魔术字符串
                    area = .5 * options.width * options.height;
                    break;  
                }
                return area;
            }
           console.log(getArea(shapeType.shape, {width: 100, height: 100})) ;
    

    如果仔细分析,可以发现,可以发现shapeType.shape等于那个值并不重要,只要确保不会和其他shapeType的属性冲突就好了。

            var shapeType = {
                shape: Symbol()
            }
            function getArea(shape, options){
                var area = 0;
                switch (shape) {
                    case shapeType.shape ://魔术字符串
                    area = .5 * options.width * options.height;
                    break;  
                }
                return area;
            }
           console.log(getArea(shapeType.shape, {width: 100, height: 100})) ;
    

    属性名的遍历

    Symbol 作为属性名,该属性名不会出现在for...in,for...of 循环中。但它也不是私有属性,有一个Objeck.getOwnPropertySymbols 方法可以获取指定对象的所有Symbol属性名。
    Objeck.getOwnPropertySymbol返回一个数组,成员是当前对象的所有用作属性名的Symbol值。

            var obj = {}, a = Symbol('a'), b = Symbol('b');
            obj[a] = 'hellow';
            obj[b] = 'word';
            obj['c'] = '111';
            var arr = Object.getOwnPropertySymbols(obj);
            console.log(arr); // [Symbol(a), Symbol(b)]
    

    将Objeck.getOwnPropertySymbols() 方法与for...in 循环,Objeck.getOwnPropertyNames方法进行了对比。

            var obj = {}, foo = Symbol('foo');
            Object.defineProperty(obj, foo , {
                value: 'foobar'
            });
    
            for (let i in obj) {
                console.log(i); //没有输出
            }
    
            console.log(Object.getOwnPropertySymbols(obj)); //[Symbol(foo)]
            console.log(Object.getOwnPropertyNames(obj)); //[]
    

    还有一个api——Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和Symbol。

            var obj = {
                [Symbol('name')]: '肖',
                age: 21
            }
            var num = Reflect.ownKeys(obj);
            console.log(num); // ["age", Symbol(name)]
    

    重新使用同一个Symbol值,Symbol.for方法可以做到这一点。它接收一个字符串为参数,然后搜索有没有以改参数命名的Symbol值,如果有,就返回该值,没有就新建并返回一个以该字符串为名称的Symbol值。

            var s = Symbol.for('foo');
            var s2 = Symbol.for('foo');
            console.log(s === s2); //true
    

    Symbol.keyFor方法返回一个已登记的Symbol类型值的key。

            var s = Symbol.for('foo');
            Symbol.keyFor(s); // "foo"
    

    Symbol值登记的名字是全局环境的,可以在不同的iframe 或 service worker中取到同一个值。

    相关文章

      网友评论

          本文标题:JavaScript之Symbol

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