JS(6).Symbol详细介绍

(一)、引出symbol

  • 在ES5中,对象的属性名都是字符串,这容易造成属性名的冲突(比如,在模块化应用中,如果你使用了一个其他人提供的对象,同时你又想为这个对象添加新的属性,这个新的属性的名字,就有可能和原来的对象中的属性名发生冲突,导致覆盖产生,如下面的例子:)
let a = {
    x:1,
    y:2
}
a['x'] = 2
console.log(a)//{x:2,y:2}
  • 如果存在一种机制,保证每个属性的名字都是独一无二的,这样就能够防止属性的冲突了。这便是ES6引入Symbol的原因了

(二)、Symbol介绍

1、Symbol()
  • ES6引入了Symbol,它为原始数据类型,表示独一无二的值
  • Symbol通过Symbol函数生成(注意:Symbol为原始数据类型,不能使用new命令)
let s1 = Symbol()
let s2 = Symbol()

console.log(s1===s2)//false
console.log(typeof s1)//'symbol'

2、Symbol()的参数
  • Symbol函数也可以接收一个字符串作为参数,表示对Symbol实例的描述,这样做的目的是利于区分:
  • 注意:Symbol()的参数只是表示对于当前Symbol值得描述,因此相同参数的Symbol的返回值是不相等的
//s1和s2都是Symbol值,如果不加参数,它们的输出都是Symbol,不利于区分
let s1 = Symbol()
let s2 = Symbol()

console.log(s1)//Symbol
console.log(s2)//Symbol

//参数只是一种描述,相同参数时,两个Symbol()的返回值并不相等
let s3 = Symbol('foo')
let S4 = Symbol('foo')

console.log(s3)//Symbol(foo)
console.log(s4)//Symbol(foo)
console.log(s3 === s4)//false

3、Symbol作为对象中的属性名:
  • ES6引入Symbol后,对象中的属性名现在可以有两种,一种是本来就有的字符串,另一种则是新增的Symbol类型。
  • 由于每个Symbol值都是不同的,这就意味着,当一个对象由模块构成时,就能够发防止莫一个键被不小心改写或覆盖
let a = {
    x:1,
    y:2
}

let x = Symbol()
a[x] = 'hello'

console.log(a)

在这里插入图片描述

  • 注意:Symbol值作为对象属性时,不能使用点运算符,因为点运算符后面接的是字符串。只能使用中括号,因为中括号内接表达式
let a = {}

let x = Symbol()
a[x] = 'hello'

console.log(a[x])//hello
console.log(a.x)//undefined

4、属性名的遍历
  • Symbol 作为属性名,该属性不会出现在 for…in 、 for…of 循环中,也不会被 Object.keys() 、 Object.getOwnPropertyNames() 、 JSON.stringify() 返回。但是,它也不是私有属性,有一个 Object.getOwnPropertySymbols 方法,可以获取指定对象的所有Symbol 属性名(以数组形式排列)。
let a = {
    x:1,
    y:2
}

let x = Symbol()
a[x] = 'hello'

for(key in a){
	console.log(key,a[key])
	/*
		x 1
		y 2
	*/
}

console.log(Object.getOwnPropertySymbols(a))//[Symbol()]

5、Symbol.for()
  • 我们希望重新使用同一个 Symbol 值, Symbol.for 方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol值。如果有,就返回这个Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
let s1 = Symbol.for('foo')
let s2 = Symbol.for('foo')
console.log(s1===s2)//true

6、Symbol()和Symbol.for()的区别、以及Symbol.keyfor()
  • Symbol()每次被调用都会生成一个新的Symbol(一位内Symbol(写法没有登记机制,所以每次调用都会返回一个不同的值)

  • Symbol.for()不会每次调用就返回一个新的Symbol,而是会先检查给定的key是否已经存在,如果不存在,则会在全局创建并注册这个key,然后才会新建一个Symbol值

  • Symbol.keyFor()方法返回一个已经登记的Symbol类型值的key

let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"

let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined

7、内置的Symbol值
  • 7.1、Symbol.hasInstance
  • 该属性可以表示一个方法:[Symbol.hasInstance](),这个方法表示一个构造器对象是否认可一个对象是它的实例。通俗点来说,就是干了instanceof的事情
function Foo(){}
let f = new Foo()
console.log(f instanceof Foo);//true
console.log(Foo[Symbol.hasInstance](f))//true


  • 7.2、Symbol.isConcatSpreadable
  • 对象的 Symbol.isConcatSpreadable 属性等于一个布尔值,表示该对象用于 Array.prototype.concat() 时,是否可以展开。
let arr1 = ['c', 'd'];
['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']
arr1[Symbol.isConcatSpreadable] // undefined

let arr2 = ['c', 'd'];
arr2[Symbol.isConcatSpreadable] = false;
['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']

  • 7.3、Symbol.match
  • 相当于String.prototype.match()方法使用,即用正则表达式去匹配字符串
String.prototype.match(regexp)
// 等同于
regexp[Symbol.match](this)

  • 7.4、Symbol.toPrimitive
  • 该属性指向一个方法,该方法表示将对象转换为相应的原始值
  • 很多内置操作都会强制将对象转换为原始值,包括字符串,数值和未指定的原始类型
  • Symbol.toPrimitive被调用时(即被内置操作强制转换时),会接受一个字符串参数(hint),表示当前运算的模式,一共有三种模式。
    • Number:该场合需要转成数值
    • String:该场合需要转成字符串
    • Default:该场合可以转成数值,也可以转成字符串
let obj = {
    [Symbol.toPrimitive](hint) {
        switch (hint) {
            case 'number':
                return 123;
            case 'string':
                return 'str';
            case 'default':
                return 'default';
            default:
                throw new Error();
        }
    }
};

//内置操作 2*obj,强制将obj转换为数值类型
2 * obj // 246

//内置操作 3+obj, 这种情况,既可以将obj转换为数值也可以转换为字符串

3 + obj // '3default'

obj == 'default' // true

//String(obj),将obj转换为字符串
String(obj) // 'str'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值