• ES6-Symbol


    Symbol

    一种新的原始数据类型,表示独一无二的值。它是JavaScript语言的第七种数据类型。

    特性

    • 表示独一无二的值
    let a = Symbol();
    let b = Symbol();
    console.log(a === b); // false
    console.log(a == b); // false
    
    • 新的原始数据类型
    var a = Symbol();
    typeof a; // "symbol"
    
    • 不能使用new关键字
    var a = new Symbol(); // 报错:Uncaught TypeError: Symbol is not a constructor
    
    • 可以接受一个字符串作为参数,表示对Symbol实例的描述
    var a = Symbol('a'); // Symbol(a)
    a.toString() // "Symbol(a)"
    
    • Symbol值不能与其他类型的值进行运算
    var a = Symbol('a');
    'hello ' + a; // 报错:Cannot convert a Symbol value to a string
    \`hello ${a}\`; // 报错:Cannot convert a Symbol value to a string
    
    • Symbol值可以显式转为字符串
    var a = Symbol('a');
    String(a); // "Symbol(a)"
    a.toString(); // "Symbol(a)"
    
    • Symbol值也可以转为布尔值。
    var a = Symbol('a');
    Boolean(a); // true
    
    • 不能转为数值
    var a = Symbol('a');
    Number(a); // 报错:Cannot convert a Symbol value to a number
    

    作为对象属性名

    • 作为属性名的几种写法
    var a = Symbol();
    
    var obj = {};
    obj[a] = 'hello';
    
    var obj = {
        [a]: 'hello'
    };
    
    var obj = {};
    Object.defineProperty(obj, a, {
        value: 'hello'
    });
    
    • Symbol值作为对象属性名时,不能用点运算符,因为点运算符后面总是字符串
    var a = Symbol();
    var obj = {};
    
    obj.a = 'hello';
    obj[a] // undefined
    obj['a'] // "hello"
    
    • 不能被for...in、for...of遍历,也不会被Object.keys()、Object.getOwnPropertyNames()等方法返回,可以通过Object.getOwnPropertySymbols()获取,或者通过Reflect.ownKey(属于ES7的范畴,它代理了大部分的Object功能,对它不再继续深入,有兴趣的同学可以自行查阅资料)
    var obj = {
        [Symbol('a')]: 'a',
        [Symbol('b')]: 'b',
        c: 'c'
    }
    
    Object.getOwnPropertyNames(obj); // []
    
    for (var i in obj) {
      console.log(i); // 无输出
    }
    
    Object.getOwnPropertySymbols(obj); // [Symbol(a), Symbol(b)]
    
    Reflect.ownKeys(obj); // ["c", Symbol(a), Symbol(b)]
    

    Symbol方法和内置Symbol值

    for()

    • 使用for方法可以获取相同Symbol值的不同变量
    • 传入的字符串需要相同,可以为空
    • 必须全为for定义
    var a = Symbol.for();
    var b = Symbol.for();
    var c = Symbol.for('c');
    var d = Symbol.for('c');
    var e = Symbol('e');
    var f = Symbol.for('e');
    
    a === b; // true
    c === d; // true
    e === f; // false
    

    keyFor()

    • 返回一个已登记的Symbol类型值的key
    • 只有通过for方法生成的Symbol才能使用该方法返回key
    var a = Symbol.for('a');
    Symbol.keyFor(a); // 'a'
    
    var a = Symbol('a'); // 未登记
    Symbol.keyFor(a); // undefined
    

    hasInstance

    • 此方法至少暂时不可用,最新版的chrome和node中均不能正常工作
    • 该方法会被instanceof运算符调用
    class Demo{
        static [Symbol.hasInstance](foo){
            return true
        }
    }
    [] instanceof Demo // 理论上返回true,但是实际chrome中测试返回false
    

    isConcatSpreadable

    • 对象的Symbol.isConcatSpreadable属性等于一个布尔值,表示该对象使用Array.prototype.concat()时,是否可以展开。
    var a = ['a']; // 数组的Symbol.isConcatSpreadable属性默认值为true
    ['b'].concat(a, 'c'); // ['b', 'a', 'c']
    
    var a = ['a'];
    a[Symbol.isConcatSpreadable] = false;
    ['b'].concat(a, 'c'); // ['b', ['a'], 'c']
    
    var a = {
        0: 'a',
        length: 1
    };
    ['c'].concat(a, 'd'); // ['c', {0: 'a', length: 1}, 'd']
    a[Symbol.isConcatSpreadable] = true;
    ['c'].concat(a, 'd'); // ['c', 'a', 'd']
    
    • 这种方法是行不通的,至少我验证了最新的chrome和最新版的node,都无法正常工作
    class Demo extends Array{[Symbol.isConcatSpreadable](){return false}}
    var a = new Demo('a');
    ['b'].concat(a); // ['b', 'a']
    

    species

    • 蛋疼啊。。。。
    • 最新版Chrome和node中验证失败
    class Demo extends Array{
        constructor(props){
            super();
            this.props = props
        }
        [Symbol.species](){
            return Array;
        }
    }
    var a = new Demo(1);
    var b = a.map(function(item, i, arr){ // 都是一个不同的数组了,咋可能还是Demo的实例呢!
        return item * 2;
    });
    b instanceof Demo; // 他们说这个地方应该返回true,但实际上返回false
    b instanceof Array;
    

    match

    • 指定字符串调用match方法时的行为
    class Match{
        constructor(props){
            this.props = props || 'hello'
        }
        [Symbol.match](string){
            return this.props.match(string);
        }
    }
    
    var match = new Match();
    'e'.match(match); // ['e']
    
    var match = new Match('111');
    'e'.match(match); // null
    

    replace

    • 指定字符串调用replace方法时的行为
    class Replace{
        [Symbol.replace](string){
            console.log(string); // 还可以干点别的哦。。
            return string.replace(/b/g, 'a');
        }
    }
    var replace = new Replace();
    'abaaaab'.replace(replace); // 'aaaaaaa'
    
    • 指定字符串调用search方法时的行为
    class Search{
        [Symbol.search](string){
            string = 'aaaaab';
            return string.search(/b/g);
        }
    }
    var search = new Search();
    'abaaaab'.search(search); // 5
    

    split

    • 指定字符串调用split方法时的行为
    class Split{
        [Symbol.split](string){
            return string.split('b', 1);
        }
    }
    var split = new Split();
    'abaaaab'.split(split); // ['a']
    

    iterator

    • 见Iterator.md

    toPrimitive

    • 当数据被进行类型转换时,调用该数据的Symbol.toPrimitive方法
    var obj = {
        [Symbol.toPrimitive](type){
            switch(type){
                case 'string': // 只能转换成string时
                    return 'aaa';
                    break;
                case 'number': // 只能转换成number时
                    return 123;
                    break;
                case 'default': // 既可以转换成string,又可以转换成number时
                    return 'default';
                    break;
                default:
                    throw new Error()
            }
        }
    }
    2 * obj // 246
    'a' + obj // 'adefault'
    String(obj) // 'aaa'
    

    toStringTag

    • 控制在调用toString方法时返回的字符串
    class Demo{
        get [Symbol.toStringTag](){
            return 'Demo'
        }
    }
    var a = new Demo();
    a.toString(); // "[object Demo]"
    

    应用

    消除魔术字符串

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

    • 魔术字符串的栗子
    function demo(str){
        switch(str){
            case 'abc': // 魔术字符串
                console.log('hello Symbol');
                break;
        }
    }
    demo('abc'); // 魔术字符串
    
    • 消除魔术字符串的方法,把它变成一个变量。大家都懂的,就没栗子了
    • 但是,上面栗子上'abc'字符串真的有实际意义吗?是否可以这样?当然也是需要赋值给一个变量
    var a = Symbol('a'); // 传字符串'a'只是为了方便查看下面的打印结果,其实可以不传
    var b = Symbol('b');
    function demo(v){
        switch(v){
            case a: 
                console.log(\`hello Symbol, I am ${String(a)}\`); // ES6的模板功能,下次再带大家认识。
                break;
            case b: 
                console.log(\`hello Symbol, I am ${String(b)}\`);
                break;
        }
    }
    demo(a);
    
  • 相关阅读:
    python中不可变数据类型和可变数据类型
    悲观锁与乐观锁
    MySql的隔离级别和锁的关系
    关于content-type请求头的说明
    数据库事务的四大特性以及事务的隔离级别
    [Vue] : 路由
    [Vue] : 组件
    [Vue] : vue-resource 实现 get, post, jsonp请求
    [Vue] : 动画
    [Vue] : 自定义指令
  • 原文地址:https://www.cnblogs.com/ddfe/p/5609733.html
Copyright © 2020-2023  润新知