• ES6-Symbol


    依赖文件地址 :https://github.com/chanceLe/ES6-Basic-Syntax/tree/master/js

      1 <!DOCTYPE html>
      2 <html>
      3     <head>
      4         <meta charset="UTF-8">
      5         <title>[es6]-09-Symbol</title>
      6         <script src="./js/browser.js"></script>
      7         <script type="text/babel">
      8             /*
      9              * es5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了别人
     10              * 提供的对象,但又想为该对象添加新属性(mixin模式),新方法的名字就有可能
     11              * 和现有的方法产生冲突。如果有一种机制,保证每个属性的名字都独一无二就好了,
     12              * 这样就从根本上防止属性名的冲突,这就是ES6引入Symbol的原因。
     13              * 
     14              * ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是js的第七种数据类型,
     15              * 前六种分别是 undefined  null String bool Number Object  (数组都是Object类型)。
     16              * 
     17              * Symbol值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来
     18              * 就有的字符串,一种是新增的Symbol类型。凡是属性名是Symbol类型,就都是独一无二的,
     19              * 保证不产生冲突。
     20              */
     21             let s = Symbol();
     22             console.log(typeof(s));  //symbol
     23             
     24             //Symbol函数前不能使用new命令,因为生成的Symbol是一个原始类型的值,而不是对象,也就是
     25             //说,由于Symbol值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
     26             
     27             //Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要为了在控制台显示,或者
     28             //转为字符串的时候,比较容易区分。
     29             
     30             let s1 = Symbol();
     31             let s2 = Symbol();
     32             console.log(s1 == s2);  //false
     33             
     34             let s3 = Symbol("foo");
     35             let s4 = Symbol("foo");
     36             console.log(s3 == s4);  //false
     37             
     38             //返回的是唯一的,且Symbol函数的参数只是起到区分说明的作用。
     39             //Symbol值不能与其他类型值运算,否则会报错。 
     40             
     41             //但可以显式转为字符串
     42             var sym = Symbol("My symbol");
     43             console.log(String(sym));     //"Symbol(My symbol)"
     44             console.log(sym.toString());   //“Symbol(My symbol)”
     45             
     46             //Symbol值也可以转为布尔值,但是不能转为数值。
     47             console.log(Boolean(sym));  //true
     48             console.log(!sym);      //false
     49             
     50             /*
     51              * 由于每个Symbol值都是不相等的,这意味着可以作为标识符,用于对象的属性名,就可以保证不会出现同名的
     52              * 属性,这对一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。
     53              * 
     54              */
     55             var mySymbol = Symbol();
     56             //1
     57             var a = {};
     58             a[mySymbol] = "hello!";
     59             //2
     60             var a = {
     61                 [mySymbol]:"hello!"
     62             }
     63             //3
     64             var a = {};
     65             Object.defineProperty(a,mySymbol,{value:"hello!"})
     66             //以上三种写法都得到同样的结果
     67             
     68             console.log(a[mySymbol]); //hello!
     69             
     70             // Symbol值作为对象的属性名时,不能用点运算符。
     71             var b = {};
     72             b.mySymbol = "hello!";
     73             console.log(b[mySymbol]);  //undefined
     74             console.log(b["mySymbol"]);  //hello!
     75             //因为点运算符后面总是字符串,所以不会读取mySymbol作为标识名指代的那个值。
     76             //导致b的属性名实际上是一个字符串,而不是一个Symbol值。
     77             
     78             //Symbol还可以定义一组常量,保证这组常量的值都是不相等的。
     79             /*
     80              * 常量使用symbol最大的好处就是其他任何值都不可能有相同的值了
     81              * 还有一点,Symbol值作为属性名时,该属性还是公开属性,不是私有属性。
     82              * 
     83              * 魔术字符串
     84              * 指的是,在代码之中多次出现,与代码形成强耦合的某一个具体的字符串或者数值,
     85              * 风格良好的代码应该尽量消除魔术字符串。改由含义清晰的变量代替。
     86              * 常用的消除魔术字符串的方法,就是把它写成一个变量。
     87              * 
     88              * 
     89              * 属性名的遍历
     90              * Symbol值作为属性名,该属性不会出现在for...in和for...of循环中,也不会被
     91              * Object.keys()  Object.getOwnPropertyNames() 中,但它不是私有属性。
     92              * 有一个Object.getOwnPropertySymbols()方法,可以获取指定对象的所有Symbol属性。
     93              */
     94             var obj = {};
     95             var a = Symbol("a");
     96             var b = Symbol("b");
     97             obj[a] = "hello!";
     98             obj[b] = "world!";
     99             var res = Object.getOwnPropertySymbols(obj);
    100             console.log(res);
    101             
    102             //另一个新的API,Reflect.ownKeys()方法可以返回所有类型的键名。包括Symbol。
    103             let obj1 = {
    104                 [Symbol("my_key")]:1,
    105                 enum:2,
    106                 nonEnum:3
    107             }
    108             console.log(Reflect.ownKeys(obj1));  //所有属性名,包括Symbol类型的。
    109             
    110             /*
    111              * 有时,我们需要使用同一个Symbol值,Symbol.for可以 做到。接受一个字符串作为参数,然后搜索
    112              * 有没有以该参数作为名称的Symbol值。如果有就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的
    113              * Symbol值。
    114              */
    115             var s5 = Symbol.for("foo");
    116             var s6 = Symbol.for("foo");
    117             console.log(s5 == s6);  //true
    118             //上面代码,两个都是Symbol值,但是他们都是同样参数的Symbol.for()方法生成的,所以实际上是同一个值。
    119             
    120             /*
    121              * Symbol.for()和Symbol()这两个写法都会生成新的Symbol。他们的区别是,前者会被登记在全局环境中供
    122              * 搜索,后者不会。Symbol.for()不会每次调用就返回一个新的Symbol类型的值,而是会先检查给定的key是否存在
    123              * 如果不存在,才会创建新值。
    124              * 
    125              * Symbol.keyFor()返回一个已登记的Symbol类型值的key。
    126              */
    127             var s7 = Symbol.for("foo");
    128             console.log(Symbol.keyFor(s7));  //"foo"
    129             
    130             var s8 = Symbol("foo");
    131             console.log(Symbol.keyFor(s8));  //undefined 因为没用for登记
    132             
    133             //要注意的是,Symbol.for()为Symbol值登记的名字,是全局环境的,可以在不同的iframe或service worker
    134             //中取到同一个值。
    135             
    136             /* 
    137              * 模块的Singleton模式
    138              * 是指调用一个类,任何时候返回的都是同一个实例。
    139              * 这个返回时的变量名可能会被覆盖,因此可以用symbol来标识。
    140              * 
    141              * 
    142              * 除了自定义自己使用的Symbol外,es6还提供了11个内置的Symbol值,指向语言内部使用的方法。
    143              * 
    144              * 1.Symbol.hasInstance   指向一个内部方法,当其他对象使用instanceof运算符,判断是否为该对象的实例时,
    145              *                        调用该方法。
    146              */
    147             class myClass{
    148                 [Symbol.hasInstance](foo){
    149                     return  foo instanceof Array;
    150                 }
    151             }
    152             console.log(
    153             [1,2,3] instanceof new myClass());  //true
    154             //instanceof 运算符会触发Symbol.hasInstance方法。
    155             
    156             /*
    157              * 2.Symbol.isConcatSpreadable  等于一个布尔值,表示该对象使用Array.prototype.concat()时,是否
    158              * 可以展开。
    159              */
    160             let arr1 = ["c","d"];
    161             console.log(["a","b"].concat(arr1,"e"));  //["a","b","c","d","e"]
    162             console.log(arr1[Symbol.isConcatSpreadable]);  //undefined
    163             
    164             let arr2 = ["c","d"];
    165             arr2[Symbol.isConcatSpreadable] = false;
    166             console.log(["a","b"].concat(arr2,"e"));   //["a","b",["c","d"],"e"] 
    167             
    168             /*
    169              * 上面的代码表明,数组的默认行为是可以展开的。Symbol.isConcatSpreadable属性等于true或undefined,
    170              * 都有这个效果。   类似数组的对象也可以展开,但Symbol.isConcatSpreadable属性默认为false,必须手动打开。
    171              */
    172             let obj2 = {length:2,0:"c",1:"d"};
    173             console.log(["a","b"].concat(obj2,"e"));   //["a","b",object,"e"]
    174             
    175             obj2[Symbol.isConcatSpreadable] = true;
    176              console.log(["a","b"].concat(obj2,"e"));   //["a","b","c","d","e"]
    177              
    178              //对于一个实例来说,Symbol.isConcatSpreadable属性必须写成实例的属性:
    179              // this[Symbol.isconacatSpreadable]=true;
    180              
    181              //其余方法,不太常用,暂时放放。
    182         </script>
    183     </head>
    184     <body>
    185     </body>
    186 </html>
  • 相关阅读:
    redis中save和bgsave区别
    go语言标准库
    numpy 学习:数组改变形状、副本和view
    Python 开始:变量、操作符、print()和type()
    numpy 学习:数据类型和空值
    Python 数据类型:布尔类型和None
    numpy 学习:数组的拼接、堆叠和拆分
    numpy 学习:数组的查找
    Databricks 第12篇:Notebook 工作流
    numpy 学习:通用函数(包含数学函数)
  • 原文地址:https://www.cnblogs.com/chengyunshen/p/7191654.html
Copyright © 2020-2023  润新知