ES6的原始类型数据——Symbol
javascript中原始值,即基本数据类型,像Number,String,Boolean,undefined,Null都是基本类型值,保存在栈中,但是有个疑问:
Symbol打印出来明明是个函数,具有prototype的属性,不能实例化的原因是:Symbol是个原始值。但Symbol明明就是个函数的鸭,而且:
Symbol.__proto__ === Function.prototype //true Symbol.constructor === Function.prototype.constructor //true Object.prototype.toString.call(Symbol) //"[object Function]" typeof Symbol //"function" typeof Symbol() //"symbol"
Symbol的原型指向的就是Function的原型,Symbol明明就是Function的实例鸭。
其实JS中检测原始值的方法就是用typeof,那么typeof Symbol返回的就是function类型。typeof Symbol(),好嘛!!!返回symbol类型。
在Javascript中函数即对象,是引用类型,为啥Symbol就是原始值,即基本类型呢?
好吧!阮一峰这里有解释说:
Symbol 值是原始类型,Symbol() 构造函数是对象。
Question:我们知道Number,Array,String,Boolean,Object都是可以进行实例化对象操作的,就是使用new操作符,思考下,number,string,boolean也是基本类型,为何就可以使用new,而Symbol()就不行呢?
解释下:symbol类型只能通过Symbol()函数的调用创建。symbol是基本类型,而Symbol()构造函数是个对象,既然是个构造器,为何就不能通过new操作符来实现一个实例化对象呢?
这里提及下Javascript的包装对象,有三种就是Boolean,Number,String。显示的创建包装对象是可以的,利用new Boolean()等方法,但是Symbol()函数对象内部阻止你显示创建一个symbol包装对象,所以你不能用new来创建一个symbol对象。只能通过Symbol("s")来创建一个基本数据类型——symbol类型。
如果你想创建一个Symbol包装对象,那么你可以先创建一个symbol基本类型值,然后通过Object()方法得到Symbol对象。"
敲黑板:
1,看栗子:
var s1 = 'abc' var s2 = 'abc' console.log(s1 === s2) //true var sym1 = Symbol('abc') var sym2 = Symbol('abc') console.log(sym1 === sym2) //false
但是Symbol.for(key)方法返回一个全局的Symbol变量,不会每次都创建新的symbol,而是返回之前已经创建的symbol。这不就是单例模式嘛!
Symbol.keyFor(sym)方法返回定义symbol类型时传入的key字符串,如果没传入则为undefined。
Object.getOwnPropertySymbols(obj):返回一个数组,数组成员是对象的所有属性名为Symbol值。
const object1 = {}; const a = Symbol('a'); const b = Symbol.for('b'); object1[a] = 'localSymbol'; object1[b] = 'globalSymbol'; const objectSymbols = Object.getOwnPropertySymbols(object1); console.log(objectSymbols) // [Symbol(a), Symbol(b)]Reflect.ownKeys(obj)
// [Symbol(a), Symbol(b)]
看阮一峰的文字呢,其实都是他自己的理解,每个人在对知识的理解上面会有些偏差,最好还是看官网吧。上面一段话意思是:Symbol()函数呢,返回一个类型为symbol的值,具有内置对象的静态属性和全局symbol的一些静态方法,类似于一个内置对象类,但是不能当做构造器函数,因为不支持“new Symbol()”语法。
每个symbol都是Symbol()函数返回的,唯一的,可以作为对象的属性名,这是symbol类型存在的唯一目的,其他用处可以去更多了解Symbol。symbol类型是原始值。
let sym = Symbol(); let obj = { [sym]:"miya" } let a = {}; Object.defineProperty(a,sym,{value:'miya'}) console.log(obj[sym]) //miya console.log(a[sym]) //miya
symbol值作为对象属性名只能通过[sym]来获取,不能通过点运算符。
对象的symbol类型属性名,只能通过Object.getOwnPropertySymbols(obj)获取,通过for...in/of或者其他都是不行的。
let s = Symbol(); let obj = { [s](args){ console.log(args) } } obj[s]('123') //123
上面的例子是:给对象obj里面添加s的属性方法,使用ES6支持的函数的写法,函数名可以使用symbol原始值类型。
阮一峰举了一个使用symbol类型来消除魔术字的例子:
const shapeType = { triangle:Symbol() } function getArea(shape,options){ let area = 0; switch(shape){ case shapeType.triangle: area = .5*options.width*options.height; break; } return area; } getArea(shapeType.triangle,{width:100,height:100}) //5000
本来shapeType.triangle是个比较长的字符串,其实字符串是什么并不重要,只要属性值不冲突就行,刚好适合symbol的适用场景。
【完】
这两天都在了解Symbol类型,从最开始的云里雾里,扒了JS的包装对象,涨了些姿势。