• 理解ES6中的Symbol


    一、为什么ES6引入Symbol

      有时候我们在项目开发的过程中可能会遇到这样的问题,我写了一个对象,而另外的同时则在这个对象里面添加了一个属性或是方法,倘若添加的这个属性或是方法是原本的对象中本来就有的,那么这个时候势必会造成冲突,那么为了防止这种冲突,ES6

    就引入了Symbol

    二、Symbol使用方法

      Symbol是一个新的数据类型,所以不要因为Symbol的使用方法的特殊而认为它只是es6中的新的方法。它所代表的是独一无二的,即便其参数一致。

      1.使用方法

        Symbol的使用方法是Symbol(描述信息),其中描述信息可以为任意类型,但若是引用类型则会调用其toString方法;若为undefined,则为Symbol(),相当于不设置描述信息;若为null则为Symbol(null)。

    let name = Symbol("jyy");
    let name1 = Symbol("jyy");
    console.log(typeof name);  // "symbol" console.log(name);  // Symbol(jyy)
    console.log(name === name1);  // 两个Symbol不相等,false

    let obj = {
    toString : function(){
    return "jyy"
    }
    };
    let obj_name = Symbol(obj);
    console.log(obj_name); // Symbol(jyy)  调用引用类型的toString

    let unf_name = Symbol(undefined);
    console.log(unf_name); // Symbol()  相当于没有设置描述信息

    let null_name = Symbol(null);
    console.log(null_name); // Symbol(null)
     

        从打印出的信息,我们可以看到,其类型是symbol。而且即便在Symbol中的描述字符串设置为相同的内容,最后二者依旧是不相等的。

      2.和其他数据类型的关系

        我们知道数据类型之间是可以互相转化的,那么Symbol和其他的数据类型之间是如何转化的?

        a. 转换为字符串

    1 let name = Symbol("jyy");
    2 console.log(String(name));  // "Symbol(jyy)"
    3 console.log(name.toString()); // "Symbol(jyy)"
    4 console.log("" + name); // 报错TypeError: Cannot convert a Symbol value to a string

          可以看出String()和toString()方法是可以转为字符串的,但是不可使用“”+Symbol()转化,回报类型错误

        b.转换为布尔值

    let name = Symbol("jyy");
    console.log(Boolean(name)); // true
    if(name){ 
      console.log(true);  // 为true
    }else{
      console.log(false);
    }

          Symbol类型只要赋值,就一定为true

      3.将对象的属性设置为Symbol类型

    let name = Symbol("jyy");
    let obj = {
      name : "beijing",
      [name] : "hebei"
    };
    console.log(obj); // { name: 'beijing', [Symbol(jyy)]: 'hebei' }
    console.log(obj.name);  // beijing
    console.log(obj["name"]); //beijing
    console.log(obj[name]); //hebei

        若对象的属性为Symbol类型,则Symbol值必须放在[]中,看代码可以体会一下

      4.对还有属性为Symbol的对象进行遍历

        若属性为Symbol类型,则该属性不会出现在for...in、for...of中,也不会通过使用Object.keys()、Object.getOwnPropertyName()得到,若想要得到,则需要使用Object.getOwnPropertySymbol()

    let name = Symbol("jyy");
    let obj = {
      name : "beijing",
      [name] : "hebei"
    };
    for(let item in obj){
      console.log(item);  // name 不能遍历Symbol类型属性
    }
    console.log(Object.keys(obj));  // [ 'name' ] 不能得到Symbol类型属性
    console.log(Object.getOwnPropertyNames(obj)); // [ 'name' ] 不能得到Symbol类型属性
    console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol(jyy) ]  只得到Symbol类型属性

        从上面的代码我们可以看到有些方法可以的得到Symbol类型,有些不行,但是却没有能够完全得到所有类型的。es6中有一个新的方法是可以得到的,如下

    let name = Symbol("jyy");
    let obj = {
      name : "beijing",
      [name] : "hebei"
    };
    console.log(Reflect.ownKeys(obj));  // [ 'name', Symbol(jyy) ]

    三、Symbol中的方法

      1.Symbol.for()

        我们知道Symbo()创建的两个变量永远不会是相同的。那么如果我们需要重新使用同一个Symbol怎么办,总不能需要挨个去进行比较吧。还好,es6为我们提供了Symbol.for()方法。 

        参数是symbol类型的描述信息,不同于Symbol(),这个而参数只能是字符串或者是undefined,若已经创建了则返回这个symbol,否则就进行创建并将这个新的symbol返回,代码如下

    let name = Symbol.for("jyy");
    let name1 = Symbol.for("jyy");
    console.log(name === name1);  // true

        请注意,我们在使用创建描述信息为jyy的变量的时候,使用的是for,而不是Symbol(),倘若使用Symbol()进行首次创建,for会再次创建一次,二者不会相等,代码如下:

    let name = Symbol("jyy");
    let name1 = Symbol.for("jyy");
    console.log(name === name1);  // false

        原因在于Symbol.for()会有一个登记机制,使用for只会对通过for创建的symbol进行检查,不会对Symbol()创建的进行检查。

      2. Symbol.keyFor()

        这个方法参数是一个通过Symbol.for()创建的symbol类型变量,返回这个symbol变量的描述信息。

    let name = Symbol.for("jyy");
    console.log(Symbol.keyFor(name)); // "jyy"
    let name1 = Symbol("jyy");
    console.log(Symbol.keyFor(name1)); // undefined 不能查找Symbol()创建的变量

      

    四、内置的Symbol属性

      1.Symbol.hasInstance

        这个属性只想一个内部方法,当该对象使用instanceof时,会调用这个方法,代码如下:

    let Animal = {
    [Symbol.hasInstance](foo){
    return true
    }
    }
    let obj = {};
    console.log(obj instanceof Animal); // true

        另外写下对于原始instaceoOf的原理:

    function instanceOf(L,R){
      var R_temp = R.prototype; // 获取右侧对象的原型对象 
      L = L.__proto__;  // 获取左侧对象的原型对象
      while(true){
        if(L == null){// 若左侧对象的原型对象是空,则返回false
          return false;
        }
        if(L === R_temp){ // 若二者的原型对象相等,则说明L是由R直接或间接创建的
          return true;
        }
        L = L.__proto__;  // 通过原型链不断向上原型对象
      }
    }

      2.Symbol.isConcatSpreadable

        这个属性为一个布尔值,用来表示该对象是否在Array.prototype.concat()时可以展开,干说不懂,代码如下:

    let arr = [1,2,3];
    let arr1 = [4,5];
    console.log(arr1[Symbol.isConcatSpreadable]); // undefined
    console.log(arr.concat(arr1));  // [ 1, 2, 3, 4, 5 ], 数组的Symbol.isConcatSpreadable默认为undefined,可以展开(true更可以)
    
    arr1[Symbol.isConcatSpreadable] = false; 
    console.log(arr.concat(arr1));  // [ 1, 2, 3, [ 4, 5, [Symbol(Symbol.isConcatSpreadable)]: false ] ]  设置为false后不可展开

      3.Symbol.match

        这个属性指向一个方法,当执行str.match(obj)时,会调用这个函数并返回其返回值,代码如下:

    class Person{
      [Symbol.match](num){
        return parseInt(num) > 100; // 自定义方法内的逻辑
      }
    }
    console.log("123".match(new Person())); // true
    console.log("12".match(new Person()));  // false

      4.Symbol.replace

        这个属性指向一个方法,当执行str.replace(obj)时,会调用这个方法并返回其返回值,代码如下:

    class Person{
      [Symbol.replace](obj,rst){  // 两个参数,第一个是对象,第二个是返回的结果
        console.log(rst); // wss
        return "hello"; // 自定义返回值
      }
    }
    
    console.log("jyy".replace(new Person(), "wss"));  // hello

      5.Symbol.toPrimitive
        这个属性指向一个方法,当对象被转为原始类型时,会调用这个方法,代码如下

    let Person = {
      [Symbol.toPrimitive](type){ // 参数为三种: string,number,default
        switch(type){
          case "string":
            return "jyy";
          case "number":
            return 28;
          default:
            return "Beijing"
        }
      }
    };
    console.log("my name: " + String(Person));  //my name: jyy
    console.log("my age: " + Number(Person));   // my age: 28
    console.log("my address is: " + Person);    // my address is: Beijing

      6.Symbol.toStringTag

        个人感觉这个方法还是比较实用的,最早看到这这个属性的使用是在webpack3打包后的js代码中,用来自定义一个方法的toString()值。我们知道当我们在aler一个对象的时候,会显示[object Object],这个属性指向的方法就是可以将Object换为自定义。代码如下:

    let person = {
      [Symbol.toStringTag] : "Person"
    }
    console.log(person.toString()); // [object Person]

        

  • 相关阅读:
    理解老板是治疗职场心态最好的药
    给青年创业者, 风险投资的十大谎言
    在尊重人的基础上发展人
    预付费
    提高记忆力的最好方法是进行记忆力训练
    九绝招巧妙应付职场各类人
    写在深夜下班路上
    25岁不得不想的问题
    谈IT技术人员的创业转摘
    职场沟通必备8个黄金句型
  • 原文地址:https://www.cnblogs.com/jyybeam/p/11974250.html
Copyright © 2020-2023  润新知