ES6 新特性梳理系列丨Symbol - 新的数据类型

本文深入探讨ES6中新增的Symbol数据类型,解析其如何解决对象属性名冲突的问题,并介绍了Symbol的多种应用场景及其与对象属性的独特交互方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ES6 新特性梳理系列文章将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!


JavaScript 与 ECMAScript

JavaScript 诞生于1995年,设计者是就职于 Netscape 公司的工程师 Brendan Eich。它是一门仅用10天就完成设计的编程语言,但至今为止已对业界保持26年的影响,且势头愈发强劲

1996年 Netscape 将 JavaScript 提交给ECMA,希望它可以成为“标准化一个通用的、跨平台的、中立于厂商的脚本语言的语法和语义标准”,1997年 ECMA 确定将 JavaScript 作为浏览器脚本语言的标准,并为之重命名为 ECMAScript,所以通常来讲我们将 ECMAScript 视为 JavaScript 的标准,而 JavaScript 则是 ECMAScript 的实现及扩展

1997年-1999年连续发布了ES1-ES3发布,2000年开始酝酿新版本的升级内容,中间因标准委员会意见未能达成一致,只做了部分功能的小范围升级及支持,于2009年12月发布了过渡版 ECMAScript 5.0,2011年6月发布 ECMAScript 5.1 并成为 ISO 国际标准

2013年3月 ECMAScript 6 草案冻结,2013年12月 ECMAScript 草案发布,2015年6月 ECMAScript 6 正式通过,成为新的国际标准。ES6 泛指自2015年升级为 ECMAScript 6.0 后的所有子版本,如:ES2015-ES2020,等同于ES6.0-ES6.5,这是 JavaScript 走向企业级编程语言的强势升级

不断升级的标准与实现,对于开发效率及产品质量起到强有力的支撑,接下来我们开始梳理ES6的新特性吧!


为什么要有 Symbol

在ES5中,由于我们的对象属性名都是字符串,所以在团队协作过程中,你声明的对象属性可能会和团队中的相同,从而导致冲突。所以我们需要一种可以声明一个变量是独一无二的方法,来保证我们的对象属性的唯一性。

Symbol 由此诞生,他可以确保我们声明的这个变量是独一无二的,从而避免了同名属性导致的冲突情况。

隐藏


什么是 Symbol

Symbol 是 ES6 引入的一种新的原始数据类型,表示独一无二的值,它最大的用法是用来定义对象的唯一属性名。

Symbol 数据类型通过 Symbol() 函数获取,但是不可以通过 new Symbol() 生成,否则会报错,因为 Symbol 还一个原始类型的值,并不是一个对象,进而不可以为 Symbol 类型的值添加属性。

以下是 Symbol 类型值的生成:

let a = Symbol()
console.log(typeof a)   // "Symbol"

Symbol() 还可以传递参数,但是这个参数仅仅起到描述作用,主要是为了在控制台显示,或者通过转为字符串以后容易区分,并无实际意义。

let a = Symbol("这个是a")
let b = Symbol("这个是b")
console.log(a)  // Symbol("这个是a")
console.log(b)  // Symbol("这个是b")
console.log(a.toString())   // "Symbol("这个是a")"
console.log(b.toString())   // "Symbol("这个是b")"

以上代码,如果不加参数进行区分的话,输出的两个变量都是 Symbol() ,不利于区分,通过参数可以明显区分不同的 Symbol 变量。


Symbol 的特征

当 Symbol 的参数是一个对象的时候,默认会返回这个对象的 toString() 值,然后以该值作为参数生成 Symbol 对象。

const a = {
  toString:function(){
    return "abc"
  }
}
let b = Symbol(a)
console.log(b)   // Symbol(abc)

每次通过 Symbol() 生成的 Symbol 对象都是独一无二的,即使你传入的参数相同,二者也是不一样的。

let a = Symbol("相同的参数")
let b = Symbol("相同的参数")
console.log(a)  // Symbol("相同的参数")
console.log(b)  // Symbol("相同的参数")
console.log(a === b)  // false

并且,Symbol 值不可以和其他值进行运算:

var a = Symbol('abc');
console.log("进行运算的字符串" + a)
// TypeError: can't convert symbol to string
console.log(`进行运算的字符串 ${a}`)
// TypeError: can't convert symbol to string

Symbol 值可以转换为字符串、Boolean 值,但是不可以转换为数字:

let a = Symbol('zifu');
console.log(String(a)_ // 'Symbol(zifu)'
console.log(a.toString()) // 'Symbol(a)
var b = Symbol();
console.log(Boolean(b)) // true
console.log(!b)   // false
console.log(Number(b))  // TypeError
console.log(b + 2)   // TypeError

Symbol()、Symbol.for() 和 Symbol.keyFor()

Symbol() 声明过的变量各个独一无二,当你声明相同参数的 Symbol 值100次,会得到100个不同的 Symbol 值。创建的 Symbol 值不会登记在全局环境中。

let a = Symbol("相同的参数")
let b = Symbol("相同的参数")
console.log(a)  // Symbol("相同的参数")
console.log(b)  // Symbol("相同的参数")
console.log(a === b)  // false

Symbol.for() 接收一个字符串作为参数,会先遍历已有的 Symbol 值中有没有以该字符串作为参数名的,如果有就将这个值返回,如果没有,就重新创建一个 Symbol 值,传入的参数作为新的 Symbol 的参数。

并且新创建的 Symbol 值会登记在全局环境中。当你通过 Symbol.for() 创建10个 Symbol 值,每次都会返回同一个 Symbol 值,最终当前环境只有一个  Symbol 值。

let a = Symbol.for("abc")
let b = Symbol.for("abc")
console.log(a === b)    // true

Symbol.keyFor() 返回一个已登记的 Symbol 值的 key,如果 Symbol 值是未登记的,则返回 undefined。

var a = Symbol.for("abc");
console.log(Symbol.keyFor(a)) // "abc"


var b = Symbol("abc");
console.log(Symbol.keyFor(b)) // undefined

Symbol 作为对象属性名

前面已经介绍过,Symbol 的主要作用是为了避免相同属性名的冲突。那么 Symbol 是如何作为属性名来使用的呢?

let sym = Symbol();


// 第一种写法
var a = {};
a[sym] = 'Hello!';


// 第二种写法
var a = {
  [sym]: 'Hello!'
};


// 第三种写法
var a = {};
Object.defineProperty(a, sym, { value: 'Hello!' });


// 以上写法都得到同样结果
a[mySymbol] // "Hello!"


注意,Symbol 值作为对象属性使用时,不可以使用点运算符,因为点运算符会将 Symbol 值当做字符串来使用。

var sym = Symbol();
var a = {};


a.sym= 'Hello!';
a[sym] // undefined
a['sym'] // "Hello!"

同理,在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。

let sym = Symbol();
let a = {
  [sym]: function (val) { 
    console.log(val)
  }
};
a[sym](123);   // 123

11个内置的 Symbol 值

1. Symbol.hasInstance 

当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法。

2. Symbol.isConcatSpreadable

对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat() 时,是否可以展开

3. Symbol.unscopables

该对象指定了使用 with 关键字时,哪些属性会被 with 环境排除

4. Symbol.match

当执行 str.match(object) 时,如果该属性存在,会调用它,返回该方法的返回值。

5. Symbol.replace

当该对象被 str.replace(object)方法调用时,会返回该方法的返回值

6. Symbol.search

当该对象被 str.search(object) 方法调用时,会返回该方法的返回值

7. Symbol.split

当该对象被 str.split(object) 方法调用时,会返回该方法的返回值

8. Symbol.iterator

对象进行 for...of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器

9. Symbol.toPrimitive

该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值

10. Symbol.toStringTag 

在该对象上面调用 toString() 方法时,返回该方法的返回值

11. Symbol.species

创建衍生对象时,会使用该属性 


ES6 新特性梳理系列文章将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!

叶阳辉

HFun 前端攻城狮

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值