前端
由于在2007年以前Js给予咱们typeof解析数据类型的一共有六种(一直有争议,可是咱们暂时就按typeof来算)es6
'function'web
'Number'json
'Object'api
'boolean'数组
'String'安全
'undefined'前端工程师
但当咱们去 typeof Symbol () 的时候,会惊奇的发现,返回了一个学习
‘symbol’测试
首先确定要有疑问,这货是啥?
固然第一种想法其实就是确定很强大。由于前六种已经强大的一种地步了,这货确定也必定很是强大。
首先咱们先带着咱们的好奇心一步一步来看看这个鬼东西。
首先先验证一下它是否是对象。
经过我先说一下我对对象研究的他有三种机制:
只要是对象就能够引用。
只要是对象均可以赋予私有属性。
对象都不相等。
那么
var a = Symbol(); a.b = 10;// 赋予私有属性 a.b // undefined
看来这货不是个对象,既然不是对象咱们来看看它的一些别的特性。
首先在 api 上 Symbol 提供了两个方法第一个是 for 另一个是 keyFor 。
var s1 = Symbol.for('abc'); var s2 = Symbol.for('abc'); Symbol() === Symbol() //false s1 === s2 //true Symbol.keyFor(s1)// 'abc'
固然这两个看起来比较容易 彷佛就是一个赋予一个值而后就会把原来的值吐出来,固然真是原来的值么?带着这样的疑问我又继续作了一些实验。
var s1 = Symbol.for([1,2,3]); Symbol.keyFor(s1); // "1,2,3" 字符串的 1,2,3 var s1 = Symbol.for(function (){}); Symbol.keyFor(s1); "function (){}" 字符串的fn;
你会发现这货你存的东西只会以字符串的东西吐出来。
固然这个东西官方说因为每个 Symbol 值都是不相等的,这意味着 Symbol 值能够做为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的状况很是有用,能防止某一个键被不当心改写或覆盖。
也就是说能够做为存在 json 中让 key 永远不相等。OK ,那么就彻底能够这样:
var a = {}; a[Symbol()]= 'Hello!'; a[Symbol()]= 'Hello!'; a[Symbol()]= 'Hello!'; console.log(a); Object Symbol(): "Hello!" Symbol(): "Hello!" Symbol(): "Hello!" __proto__: Object
你会发现出现了连续的三个 a的属性 都是hello 而且没有覆盖 。也就是说这么写的话能够有效的防止其json重名问题,不过拿起来就很是费劲了。
for(var i in a){ console.log(i +',' +a[i]) //没有任何的东西 }
固然这就比较能够可疑了,json 用 symbol 存上东西了,可是又用 for in 拿不到。也就说若是直接这么赋值 json 认,可是 for in 循环不认,并且我们也拿不到。
可是换一种方式就没问题了。用变量存的话,虽然虽然 for in 拿不到,可是我们能够拿到值。
var a = Symbol('aaa'); b = {}; b[a] = 10 ; console.log(b[a])//10
轻松拿到值。其实不难看出来 Symbol 对 for in 不是很友好,可是 对 json 很友好。
这时若是使用别的方法拿值呢?顾名思义,Object.getOwnPropertyNames() 是拿对象私有属性的的方法,咱们来试试。
let b = {}; b[Symbol()]=10; b[Symbol()]=15; Object. getOwnPropertyNames(b) //
能够理解为:其实 Symbol 不做为 b 的私有属性存在。拿能不能拿到呢?其实也能拿到。他提供了一个 getOwnPropertySymbols 方法可让我找到存在内存里的 Symbol 。
例如:
let a = {}; a[Symbol()]=10; a[Symbol()]=15; Object.getOwnPropertySymbols(a) //[Symbol(),Symbol()] //这里面以数组的形式返回了 我们使用的两个Symbol(); Object.getOwnPropertySymbols(a)[0]//Symbol() 第一个Symbol() a[Object.getOwnPropertySymbols(a)[0]]//10 拿到存在的这个值。
其实知道是数组后 咱们就能够循环 obj.getOwnPropertySymbols(a) 这个东西 而后输出值了。其实说回来只是换了一种方法拿值,存值。而这种方法更安全更隐蔽而已。
而Symbol还有一些比较特殊的特性。js中的~(按位非) 是一个比较强势的转换number的东西。
例如:
~NaN //-1 ~function (){}//-1 ~undefined //-1 var a = function (){}; ~a() //-1 ~new a() //-1
基本任何东西都能转成number,而:
~Symbol //-1 ~Symbol() //报错
彷佛说明了 其跟function 有着本质的区别,另外呢,Symbol值不能与其余类型的值进行运算,会报错。
var sym = Symbol('My symbol'); "your symbol is " + sym // TypeError: can't convert symbol to string es5以前的报错 `your symbol is ${sym}` // TypeError: can't convert symbol to string es6字符串照样的报错
另外,Symbol值也能够转为布尔值,可是不能转为数值。这些都是Symbol的一些小特性。
var sym = Symbol(); Boolean(sym) // true !sym // false Number(sym) // TypeError sym + 2 // TypeError
其实来讲Symbol做为一个新的数据类型 最强的而不是干以上的这些事而是一些配合原型方法的一些开关,能够强化方法的使用。
好比说 Symbol.isConcatSpreadable 这个方法,我们都知道 正常的数组concat方法是链接字符串。
let arr = ['c', 'd']; ['a', 'b'].concat(arr2,'e') //['a','b','c','d','e'];
而咱们一旦把开关打开后会发现一些意想不到的结果。
let arr2 = ['c', 'd']; arr2[Symbol.isConcatSpreadable] = false; ['a', 'b'].concat(arr2, 'e') //['a','b',['c','d'],'e']
会发现以数组的形式插入到里面了。固然他还包括了一些别的方法,例如,他能够测试 ES6 新增的内置对象方法 Symbol.toStringTag 。
JSON[Symbol.toStringTag]:'JSON' Math[Symbol.toStringTag]:'Math' Module对象M[Symbol.toStringTag]:'Module' ArrayBuffer.prototype[Symbol.toStringTag]:'ArrayBuffer' DataView.prototype[Symbol.toStringTag]:'DataView' Map.prototype[Symbol.toStringTag]:'Map' Promise.prototype[Symbol.toStringTag]:'Promise' Set.prototype[Symbol.toStringTag]:'Set' %TypedArray%.prototype[Symbol.toStringTag]:'Uint8Array'等 WeakMap.prototype[Symbol.toStringTag]:'WeakMap' WeakSet.prototype[Symbol.toStringTag]:'WeakSet' %MapIteratorPrototype%[Symbol.toStringTag]:'Map Iterator' %SetIteratorPrototype%[Symbol.toStringTag]:'Set Iterator' %StringIteratorPrototype%[Symbol.toStringTag]:'String Iterator' Symbol.prototype[Symbol.toStringTag]:'Symbol' Generator.prototype[Symbol.toStringTag]:'Generator' GeneratorFunction.prototype[Symbol.toStringTag]:'GeneratorFunction'
不过,用 ES5 以前的方法依然也能够检验出来内置对象,因此 Symbol 就是更规范化而已,就用 map 举例。
Object.prototype.toString.call(new Map())//'[object Map]'
别的内置对象也是同理。Symbol.unscopables 也是Symbol一个比较有意思的东西。能够找到对象内哪些属性被with排除。
Object.keys(Array.prototype[Symbol.unscopables])//['copyWithin', 'entries', 'fill', 'find', 'findIndex', 'keys']
以数组的形式返回 也就是说 这些属性会被with排除。其实这些只是Smybol的冰山一角,更多的是Symbol是服务于ES6中。让咱们继续慢慢探索好了。
更多学习内容请阅读个人知乎专栏: 打造全网web高级前端工程师资料库(总目录)看完学的更加快,知识更牢固。你值得拥有(持续更新)~