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
  console.log(Symbol.for('foo') === Symbol.for('foo'));//true

但是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的包装对象,涨了些姿势。

posted @ 2018-11-29 17:45  tangjiao_Miya  阅读(1009)  评论(0编辑  收藏  举报