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>

 

转载于:https://www.cnblogs.com/chengyunshen/p/7191654.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值