ES6中Symbol的理解和使用

什么是Symbol

  Symbol是由ES6规范引入的一项新特性,它是一种新的基础数据类型,它的功能类似于一种标识唯一性的ID。通常情况下,我们可以通过调用Symbol()函数来创建一个Symbol实例:

	let s1 = Symbol()
	
	或者,你也可以在调用Symbol()函数时传入一个可选的字符串参数,相当于给你创建的Symbol实例一个描述信息:
	let s2 = Symbol('another symbol')

	由于Symbol是一种基础数据类型,所以当我们使用typeof去检查它的类型的时候,它会返回一个属于自己的类型symbol,而不是什么string、object之类的:
	typeof s1  // 'symbol'
	
	另外 每个Symbol实例都是唯一的 ,所以当你比较两个Symbol实例的时候,将总会返回false:
	const a=Symbol("name");
    const b=Symbol("name");
    console.log(a===b) //false

应用场景1:使用symbol作为对象属性名

    const name=Symbol();
    const age=Symbol();
    let obj={
         [name]:"已经代码"
    }
    obj[age]=18;
    console.log(obj[name]);//已经代码
    console.log(obj[age]);//18

  并且 当使用了Symbol作为对象的属性key后不能使用枚举方法

    const name=Symbol();
    const age=Symbol();
    const obj={
        [name]:"大师",
        [age]:16,
        sex:"男"
    }
    console.log(obj)
    console.log(Object.keys(obj));//["sex"]  使用symbol定义的属性,不能使用枚举遍历
    for(let p in obj){
        console.log(p); // sex
    }
    // 使用Object的API
    console.log(Object.getOwnPropertyNames(obj));// ["sex"] 得到符号类型代替的属性名,并且为数组

    console.log(Object.getOwnPropertySymbols(obj));// [Symbol(), Symbol()]
    const sybs=Object.getOwnPropertySymbols(obj);
    console.log(sybs[0]===name) //true 引用会相等
    
    //补充:
	1.Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
    2.Object.getOwnPropertySymbols()方法返回一个给定对象自身的所有 Symbol 属性的数组。

应用场景2:使用Symbol定义类的私有属性/方法

    const Hero=(()=>{
        const getRandom=Symbol();
        return class Person{
            constructor(a,b,c){
                this.a=a;
                this.b=b;
                this.c=c;
            }
            gongji(){
                // const gj=
            }
            [getRandom](max,min){
                return Math.random()*(max-min)+min;
            }
        }
    })()
    var per=new Hero(10,20,30,40);
    console.log(per); //Person {a: 10, b: 20, c: 30}
    // console.log(per[getRandom](10,20)); //报错
    
    // 上面这种方法调用不到,因为现在的[getRandom]在Hero的原型上
    
    const sybs=Object.getOwnPropertySymbols(Hero.prototype)
    console.log(sybs); //所以要访问Hero的原型才可以调用输出到

Symbol内置的属性值

Symbol.hasInstance:其它对象使用instanceof运算符的时候会使用该属性名指向的内部方法。

Symbol.isConcatSpreadable:可以直接定义为对象属性或继承而来,它是布尔类型。它可以控制数组或类似数组(array-like)的对象的行为:
	1.对于数组对象,默认情况下,用于concat时,会按数组元素展开然后进行连接(数组元素作为新数组的元素)。重置Symbol.isConcatSpreadable可以改变默认行为。
	2.对于类似数组的对象,用于concat时,该对象整体作为新数组的元素,重置Symbol.isConcatSpreadable可改变默认行为。
	
Symbol.species:species 访问器属性允许子类覆盖对象的默认构造函数。

Symbol.match:指定了匹配的是正则表达式而不是字符串。String.prototype.match() 方法会调用此函数。此函数还用于标识对象是否具有正则表达式的行为。
		比如, String.prototype.startsWith(),String.prototype.endsWith() 和 String.prototype.includes() 
	这些方法会检查其第一个参数是否是正则表达式,是正则表达式就抛出一个TypeError。现在,如果 match symbol 设置为
	false(或者一个 假值),就表示该对象不打算用作正则表达式对象。

Symbol.replace:这个属性指定了当一个字符串替换所匹配字符串时所调用的方法。

Symbol.search:指定了一个搜索方法,这个方法接受用户输入的正则表达式,返回该正则表达式在字符串中匹配到的下标,这个方法由以下的方法来调用 String.prototype.search()。

Symbol.split:指向 一个正则表达式的索引处分割字符串的方法。

Symbol.iterator:为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。

Symbol.toPrimitive:是一个内置的 Symbol 值,它是作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。

Symbol.toStringTag:是一个内置 symbol,它通常作为对象的属性键使用,对应的属性值应该为字符串类型,这个字符串用来表示该对象的自定义类型标签,通常只有内置的 Object.prototype.toString() 方法会去读取这个标签并把它包含在自己的返回值里。

Symbol.unscopables:指用于指定对象值,其对象自身和继承的从关联对象的 with 环境绑定中排除的属性名称。

部分方法及案例

1.Symbol.for()
  Symbol.for(key) 会根据给定的键 key,来从运行时的 symbol 注册表中找到对应的 symbol,如果找到了,则返回它,否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中。

示例:
	Symbol.for("foo"); // 创建一个 symbol 并放入 symbol 注册表中,键为 "foo"
	Symbol.for("foo"); // 从 symbol 注册表中读取键为"foo"的 symbol

	Symbol.for("bar") === Symbol.for("bar"); // true,证明了上面说的
	Symbol("bar") === Symbol("bar"); // false,Symbol() 函数每次都会返回新的一个 symbol

	var sym = Symbol.for("mario");
	sym.toString(); 
	// "Symbol(mario)",mario 既是该 symbol 在 symbol 注册表中的键名,又是该 symbol 自身的描述字符串

2.Symbol.keyFor()
  Symbol.keyFor(sym) 方法用来获取 symbol 注册表中与某个 symbol 关联的键。

示例:
	// 创建一个 symbol 并放入 Symbol 注册表,key 为 "foo"
	var globalSym = Symbol.for("foo"); 
	Symbol.keyFor(globalSym); // "foo"
	
	// 创建一个 symbol,但不放入 symbol 注册表中
	var localSym = Symbol(); 
	Symbol.keyFor(localSym); // undefined,所以是找不到 key 的
	
	// well-known symbol 们并不在 symbol 注册表中
	Symbol.keyFor(Symbol.iterator) // undefined

3.Symbol.toString()
  返回当前 symbol 对象的字符串表示。

symbol 原始值不能转换为字符串,所以只能先转换成它的包装对象,再调用 toString() 方法:

	Symbol("foo") + "bar";      
	// TypeError: Can't convert symbol to string
	Symbol("foo").toString() + "bar"
	// "Symbol(foo)bar",就相当于下面的:
	Object(Symbol("foo")).toString() + "bar"
	// "Symbol(foo)bar"

示例:
	Symbol("desc").toString();   // "Symbol(desc)"

	// well-known symbols
	Symbol.iterator.toString();  // "Symbol(Symbol.iterator)
	
	// global symbols
	Symbol.for("foo").toString() // "Symbol(foo)"

4.Symbol.valueOf()
  方法返回当前 symbol 对象所包含的 symbol 原始值。

  在 JavaScript 中,虽然大多数类型的对象在某些操作下都会自动的隐式调用自身的 valueOf() 方法或者 toString() 方法来将自己转换成一个原始值,但 symbol 对象不会这么干,symbol 对象无法隐式转换成对应的原始值:

	Object(Symbol("foo")) + "bar";
	// TypeError: can't convert symbol object to primitive
	// 无法隐式的调用 valueOf() 方法
	
	Object(Symbol("foo")).valueOf() + "bar";
	// TypeError:  can't convert symbol to string
	// 手动调用 valueOf() 方法,虽然转换成了原始值,但 symbol 原始值不能转换为字符串
	
	Object(Symbol("foo")).toString() + "bar";
	// "Symbol(foo)bar",需要手动调用 toString() 方法才行
  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值