1. 首页
  2. IT资讯

「ES6基础」Symbol介绍:独一无二的值

“u003Cdivu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002Ff1fd2ec1f6c04a629c7f3257892ace7c” img_width=”900″ img_height=”383″ alt=”「ES6基础」Symbol介绍:独一无二的值” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003EES6之前我们都清楚JS有六种数据类型:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object),今天笔者讲的Symbol类型是ES6才加入的,它最大的特点就如标题所说“独一无二”。u003Cu002Fpu003Eu003Cpu003E本篇文章笔者将从以下几个方面进行介绍:u003Cu002Fpu003Eu003Culu003Eu003Cliu003E值类型和引用类型介绍u003Cu002Fliu003Eu003Cliu003E如何声明一个Symbol?u003Cu002Fliu003Eu003Cliu003E为什么要有Symbol?u003Cu002Fliu003Eu003Cliu003ESymbol的常用用法u003Cu002Fliu003Eu003Cliu003E内置常用Symbol值的用法u003Cu002Fliu003Eu003Cu002Fulu003Eu003Cpu003E本篇文章阅读时间预计u003Cstrongu003E15u003Cu002Fstrongu003E分钟。u003Cu002Fpu003Eu003Ch1u003E值类型和引用类型介绍u003Cu002Fh1u003Eu003Cpu003E在了解Symbol之前,我们需要了解下JS的数据类型,在JS中数据类型分为两类:值类型和引用类型。u003Cu002Fpu003Eu003Culu003Eu003Cliu003E值类型:数值型(Number),字符类型(String),布尔值型(Boolean),null 和 underfinedu003Cu002Fliu003Eu003Cliu003E引用类型:对象(Object)u003Cu002Fliu003Eu003Cu002Fulu003Eu003Cpu003E所谓的值类型可以这样理解:变量之间的互相赋值,是指开辟一块新的内存空间,将变量值赋给新变量保存到新开辟的内存里面;之后两个变量的值变动互不影响。u003Cu002Fpu003Eu003Cpu003E如下段代码所示:u003Cu002Fpu003Eu003Cpreu003Elet weChatName =”前端达人”; u003Cbru003Eu002Fu002F开辟一块内存空间保存变量 weChatName 的值“前端达人”;u003Cbru003Elet touTiao =weChatName; u003Cbru003Eu002Fu002F给变量 touTiao 开辟一块新的内存空间,将 weChatName 的值 “前端达人” 赋值一份保存到新的内存里;u003Cbru003Eu002Fu002FweChatName 和 touTiao 的值以后无论如何变化,都不会影响到对方的值;u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E一些语言,比如 C,有引用传递和值传递的概念。JS 也有类似的概念,它是根据传递的数据类型推断的。如果将值传递给函数,则重新分配该值不会修改调用位置中的值。但是,如果你修改的是引用类型,那么修改后的值也将在调用它的地方被修改。u003Cu002Fpu003Eu003Cpu003E所谓的引用类型可以这样理解:变量之间的互相赋值,只是指针的交换,而并非将对象复制一份给新的变量,对象依然还是只有一个,只是多了一个指引~~;u003Cu002Fpu003Eu003Cpu003E如下段代码所示:u003Cu002Fpu003Eu003Cpreu003Elet weChat = { name: “前端达人”, regYear:”2014″ }; u003Cbru003Eu002Fu002F需要开辟内存空间保存对象,变量 weChat 的值是一个地址,这个地址指向保存对象的空间;u003Cbru003Elet touTiao= weChat; u003Cbru003Eu002Fu002F 将 weChat 的指引地址赋值给 touTiao,而并非复制一给对象且新开一块内存空间来保存;u003Cbru003EweChat.regYear=”2018″;u003Cbru003Econsole.log(touTiao);u003Cbru003Eu002Fu002Foutput:{ name: ‘前端达人’, regYear: ‘2018’ }u003Cbru003Eu002Fu002F 这个时候通过 weChat 来修改对象的属性,则通过 touTiao 来查看属性时对象属性已经发生改变;u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E那Symbol是什么数据类型呢?这里笔者先告诉大家是u003Cstrongu003E值类型u003Cu002Fstrongu003E,下面会有详细的介绍。u003Cu002Fpu003Eu003Ch1u003Eu003Cstrongu003E如何声明一个Symbol?u003Cu002Fstrongu003Eu003Cu002Fh1u003Eu003Cpu003ESymbol最大的特点就如本篇文章的标题一样:独一无二。这个独一无二怎么解释呢?就好比双胞胎,外表看不出差别,但是相对个体比如性格爱好还是有差异的,每个人都是独一无二。Symbol表示独一无二的值,是一种互不等价标识,声明Symbol十分简单,如下段代码所示:u003Cu002Fpu003Eu003Cpreu003Econst s = Symbol();u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003ESymbol([description]) 声明方式,支持一个可选参数,只是用于描述,方便我们开发调试而已。每次执行Symbol()都会生成一个独一无二的Symbol值,如下段代码所示:u003Cu002Fpu003Eu003Cpreu003Elet s1 = Symbol(“My Symbol”);u003Cbru003Elet s2 = Symbol(“My Symbol”);u003Cbru003Econsole.log(s1 === s2); u002Fu002F Outputs false”u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E由此可见,即使Symbol的描述值参数相同,它们的值也不相同,描述值仅仅是起描述的作用,不会对Symbol值本身起到任何的改变。关于描述值需要注意的一点:接受u003Cstrongu003E除Symbol值u003Cu002Fstrongu003E以外所有的值,怎么理解呢,请看下段代码所示:u003Cu002Fpu003Eu003Cpreu003Econst symbol = Symbol();u003Cbru003Econst symbolWithString=Symbol(‘前端达人’);u003Cbru003Eu002Fu002FSymbol(前端达人)u003Cbru003Econst SymbolWithNum=Symbol(3.14); u003Cbru003Eu002Fu002FSymbol(3.14)u003Cbru003Econst SymbolWithObj=Symbol({foo:’bar’});u003Cbru003Eu002Fu002FSymbol([object Object])u003Cbru003Econst anotherSymbol=Symbol(symbol); u003Cbru003Eu002Fu002FTypeError: Cannot convert a Symbol value to a stringu003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E接下来笔者来详细解释下,为什么Symbol是值类型,而不是引用类型。Symbol函数并不是构造函数,因此不能使用new方法来生成一个Symbol对象,否则编译器会抛出异常,如执行下段代码所示:u003Cu002Fpu003Eu003Cpreu003Enew Symbol();u003Cbru003Eu002Fu002FTypeError: Symbol is not a constructoru003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E由此可见,Symbol是一种值类型而非引用类型,这就意味着如果将Symbol作为参数传值的话,将会是值传值而非引用传值,如下段代码所示(值的改变没有互相影响):u003Cu002Fpu003Eu003Cpreu003Econst symbol=Symbol(‘前端达人’);u003Cbru003Efunction fn1(_symbol) {u003Cbru003E return _symbol==symbol;u003Cbru003E}u003Cbru003Econsole.log(fn1(symbol));u003Cbru003Eu002Fu002Foutput:true;u003Cbru003Efunction fn2(_symbol) {u003Cbru003E _symbol=null;u003Cbru003E console.log(_symbol);u003Cbru003E}u003Cbru003Efn2(symbol);u003Cbru003Eu002Fu002Foutput:null;u003Cbru003Econsole.log(symbol);u003Cbru003Eu002Fu002FSymbol(前端达人)u003Cbru003Eu003Cu002Fpreu003Eu003Ch1u003Eu003Cstrongu003E为什么要有Symbol?u003Cu002Fstrongu003Eu003Cu002Fh1u003Eu003Cpu003E介绍了这么多,Symbol存在的意义是什么?笔者先举个简单的业务场景:u003Cu002Fpu003Eu003Cpu003E在前端的JavaScript应用开发中,需要先通过渲染引擎所提供的API来获取一个DOM元素对象,并保留在JavaScript运行时中。因为业务需要,需要通过一个第三方库对这个DOM元素对象进行一些修饰和调整,即对该DOM元素对象进行一些新属性的插入。u003Cu002Fpu003Eu003Cpu003E而后来因为新需求的出现,需要再次利用另外一个第三方库对同一个DOM元素对象进行修饰。但非常不巧的是这个第三方库同样需要对该DOM元素对象进行属性插入,而恰好这个库所需要操作的属性与前一个第三方库所操作的属性相同。这种情况下就很有可能会出现两个第三方库都无法正常运行的现象,而使用这些第三方库的开发者却难以进行定位和修复。u003Cu002Fpu003Eu003Cpu003E针对上述问题, Symbol可以提供一种良好的解决方案。这是因为Symbol的实例值带有互不等价的特性,即任意两个Symbol值都不相等。在ES2015标准中,字面量对象除了可以使用字符串、数字作为属性键以外,还可以使用Symbol作为属性键,因此便可以利用Symbol值的互不等价特性来实现属性操作的互不干扰了。u003Cu002Fpu003Eu003Ch1u003Eu003Cstrongu003ESymbol的常用用法u003Cu002Fstrongu003Eu003Cu002Fh1u003Eu003Cpu003Eu003Cstrongu003E1、判断是否是Symbolu003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E如何判断一个变量是不是Symbol类型呢?目前唯一的方法就是使用typeof,如下段代码所示:u003Cu002Fpu003Eu003Cpreu003Econst s = Symbol();u003Cbru003Econsole.log(typeof s); u003Cbru003Eu002Fu002FOutputs “symbol”u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E2、用作对象的属性u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E通常我们使用字符串定义对象的属性(Key),有了Symbol类型后,我们当然可以使用Symbol作为对象的属性,唯一不同的地方,我们需要使用[]语法定义属性,如下段代码所示:u003Cu002Fpu003Eu003Cpreu003Econst WECHAR_NAME = Symbol();u003Cbru003Econst WECHAR_REG = Symbol();u003Cbru003Elet obj = {u003Cbru003E [WECHAR_NAME]: “前端达人”;u003Cbru003E}u003Cbru003Eobj[WECHAR_REG] = 2014;u003Cbru003Econsole.log(obj[WECHAR_NAME]) u002Fu002Foutput: 前端达人u003Cbru003Econsole.log(obj[WECHAR_REG]) u002Fu002Foutput:2014u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E还有一点需要强调的是,使用Symbol作为对象的Key值时,具有私有性,我们无法通过枚举获取Key值,如下段代码所示:u003Cu002Fpu003Eu003Cpreu003Elet obj = {u003Cbru003E weChatName:’前端达人’,u003Cbru003E regYear: 2014,u003Cbru003E [Symbol(‘pwd’)]: ‘wjqw@$#sndk9012’,u003Cbru003E}u003Cbru003Econsole.log(Object.keys(obj)); u003Cbru003Eu002Fu002F [‘weChatName’, ‘regYear’]u003Cbru003Efor (let p in obj) {u003Cbru003E console.log(p) u003Cbru003E u002Fu002F 分别会输出:’weChatName’ 和 ‘regYear’u003Cbru003E}u003Cbru003Econsole.log(Object.getOwnPropertyNames(obj)); u003Cbru003Eu002Fu002F [ ‘weChatName’, ‘regYear’ ]u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E从上述代码中,可以看出Symbol类型的key是不能通过Object.keys()或者for…in来枚举的,它未被包含在对象自身的属性名集合(property names)之中。利用该特性,我们可以把一些不需要对外操作和访问的属性可以使用Symbol来定义。由于这一特性的存在,我们使用JSON.stringify()将对象转换成JSON字符串的时候,Symbol属性也会被排除在输出内容之外,在上述代码中执行下段代码:u003Cu002Fpu003Eu003Cpreu003Econsole.log(JSON.stringify(obj));u003Cbru003Eu002Fu002Foutput:{“weChatName”:”前端达人”,”regYear”:2014}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E基于这一特性,我们可以更好的去设计我们的数据对象,让“对内操作”和“对外选择性输出”变得更加灵活。u003Cu002Fpu003Eu003Cpu003E我们难道就没有办法获取Symbol方式定义的对象属性了么?私有并不是绝对的,我们可以通过一些API函数进行获取,在上述代码中执行下段代码:u003Cu002Fpu003Eu003Cpreu003Eu002Fu002F 使用Object的APIu003Cbru003Econsole.log(Object.getOwnPropertySymbols(obj)); u002Fu002F [Symbol(pwd)]u003Cbru003Eu002Fu002F 使用新增的反射APIu003Cbru003Econsole.log(Reflect.ownKeys(obj));u002Fu002F [Symbol(pwd), ‘age’, ‘title’]u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E3、定义类的私有属性u002F方法u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E我们都清楚在JS中,是没有如Java等面向对象语言的访问控制关键字private的,类上所有定义的属性或方法都是可公开访问的。上面笔者讲到作为对象属性具有私有性的特点,我们定义类的私有属性和方法才能实现,如下段代码所示:u003Cu002Fpu003Eu003Cpu003E我们先建立一个a.js的文件,如下所示:u003Cu002Fpu003Eu003Cpreu003Econst PASSWORD = Symbol();u003Cbru003Eclass Login {u003Cbru003E constructor(username, password) {u003Cbru003E this.username = username;u003Cbru003E this[PASSWORD] = password;u003Cbru003E }u003Cbru003E checkPassword(pwd) {u003Cbru003E return this[PASSWORD] === pwd;u003Cbru003E }u003Cbru003E}u003Cbru003Eexport default Login;u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E我们在建立一个文件b.js,引入a.js文件,如下所示:u003Cu002Fpu003Eu003Cpreu003Eimport Login from ‘.u002Fa.js’;u003Cbru003Econst login = new Login(‘admin’, ‘123456’);u003Cbru003Econsole.log(login.checkPassword(‘123456’)); u002Fu002F trueu003Cbru003Econsole.log(login.PASSWORD); u002Fu002F undefinedu003Cbru003Econsole.log(login[PASSWORD]);u002Fu002F PASSWORD is not definedu003Cbru003Econsole.log(login[“PASSWORD”]); u002Fu002F undefinedu003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E由于Symbol常量PASSWORD被定义在a.js所在的模块中,外面的模块获取不到这个Symbol,也不可能再创建一个一模一样的Symbol出来(因为Symbol是独一无二的),因此这个PASSWORD的Symbol只能被限制在a.js内部使用,所以使用它来定义的类属性是没有办法被模块外访问到的,从而实现了私有化的效果。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E4、创建共享Symbolu003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E虽然Symbol是独一无二的,但是有些业务场景,我们需要共享一个Symbol,我们如何实现呢?这种情况下,我们就需要使用另一个API来创建或获取Symbol,那就是Symbol.for(),它可以注册或获取一个全局的Symbol实例,如下段代码所示:u003Cu002Fpu003Eu003Cpreu003Elet obj = {};u003Cbru003E(function(){u003Cbru003E let s1 = Symbol(“name”);u003Cbru003E obj[s1] = “Eden”;u003Cbru003E})();u003Cbru003Econsole.log(obj[s1]);u003Cbru003Eu002Fu002FSyntaxError: Unexpected identifier cannot be accessed hereu003Cbru003E(function(){u003Cbru003E let s2 = Symbol.for(“age”);u003Cbru003E obj[s2] = 27;u003Cbru003E})();u003Cbru003Econsole.log(obj[Symbol.for(“age”)]); u002Fu002FOutput “27”u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E从上述代码可以看出,Symbol.for()会注册一个全局作用域的Symbol值,如果这个Key值从未使用则会进行创建注册,如果已被注册,则会返回一个与第一次使用创建的Symbol值等价的Symbol,如下段代码所示:u003Cu002Fpu003Eu003Cpreu003Econst symbol=Symbol.for(‘foo’);u003Cbru003Econst obj={};u003Cbru003Eobj[symbol]=’bar’;u003Cbru003Econst anotherSymbol=Symbol.for(‘foo’);u003Cbru003Econsole.log(symbol===anotherSymbol);u003Cbru003Eu002Fu002Foutput:trueu003Cbru003Econsole.log(obj[anotherSymbol]);u003Cbru003Eu002Fu002Foutput:baru003Cbru003Eu003Cu002Fpreu003Eu003Ch1u003Eu003Cstrongu003E常用Symbol值及意义u003Cu002Fstrongu003Eu003Cu002Fh1u003Eu003Cpu003E我们除了可以自行创建Symbol值以外,ES6还将其应用到了ECMAScript引擎的各个角落,我们可以运用这些常用值对底层代码的实现逻辑进行修改,以实现更高级的定制化的需求。u003Cu002Fpu003Eu003Cpu003E以下表格进行了常用Symbol值的总结:u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002F95ca4e2c569743daa058121f11996854″ img_width=”1446″ img_height=”2168″ alt=”「ES6基础」Symbol介绍:独一无二的值” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003Eu003Cstrongu003E1、Symbol.iteratoru003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E我们可以使用Symbol.iterator来自定义一个可以迭代的对象,我们可以使用Symbol.iterator作为方法名的方法属性,该方法返回一个迭代器(Iterator)。虽然JS中没有协议(Protocal)的概念,我们可以将迭代器看做成一个协议,即迭代器协议(Iterator Protocal),该协议定义了一个方法next(),含义是进入下一次迭代的迭代状态,第一次执行即返回第一次的迭代状态,该迭代状态有两个属性,如表格所示:u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fpgc-imageu002Fb982785f2263421cb61db6a46fdbf305″ img_width=”1460″ img_height=”278″ alt=”「ES6基础」Symbol介绍:独一无二的值” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E以下是我们使用Symbol.iterator带迭代的方法,如下段代码所示:u003Cu002Fpu003Eu003Cpreu003Elet obj = {u003Cbru003E array: [1, 2, 3, 4, 5],u003Cbru003E nextIndex: 0,u003Cbru003E [Symbol.iterator]: function(){u003Cbru003E return {u003Cbru003E array: this.array,u003Cbru003E nextIndex: this.nextIndex,u003Cbru003E next: function(){u003Cbru003E return this.nextIndex < this.array.length ?u003Cbru003E {value: this.array[this.nextIndex++], done: false} :u003Cbru003E {done: true};u003Cbru003E }u003Cbru003E }u003Cbru003E }u003Cbru003E};u003Cbru003Elet iterable = obj[Symbol.iterator]();u003Cbru003Econsole.log(iterable.next().value);u003Cbru003Econsole.log(iterable.next().value);u003Cbru003Econsole.log(iterable.next().value);u003Cbru003Econsole.log(iterable.next().value);u003Cbru003Econsole.log(iterable.next().value);u003Cbru003Econsole.log(iterable.next().done);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E以上代码将会输出:u003Cu002Fpu003Eu003Cpreu003E1u003Cbru003E2u003Cbru003E3u003Cbru003E4u003Cbru003E5u003Cbru003Etrueu003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E除了可以自定义迭代的逻辑,我们也可以使用引擎默认的迭代,从而节省了我们的代码量,如下段代码所示:u003Cu002Fpu003Eu003Cpreu003Econst arr = [1, 2];u003Cbru003Econst iterator = arr[Symbol.iterator](); u002Fu002F returns you an iteratoru003Cbru003Econsole.log(iterator.next());u003Cbru003Econsole.log(iterator.next());u003Cbru003Econsole.log(iterator.next());u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E以上代码将会输出u003Cu002Fpu003Eu003Cpreu003E{ value: 1, done: false }u003Cbru003E{ value: 2, done: false }u003Cbru003E{ value: undefined, done: true }u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E2、Symbol.hasInstanceu003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E用于为类定义一个方法。该方法会因为instanceof语句的使用而被调用,来检查一个对象是否是某一个类的实例, 用于扩展instanceof的内部逻辑,我们可以用于为一个类定一个静态方法,该方法的第一个形参便是被检测的对象,而自定义的方法内容决定了instanceof语句的返回结果,代码如下:u003Cu002Fpu003Eu003Cpreu003Eclass Foo{u003Cbru003E static [Symbol.hasInstance](obj){u003Cbru003E console.log(obj);u003Cbru003E return true;u003Cbru003E }u003Cbru003E}u003Cbru003Econsole.log( {} instanceof Foo);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E以上代码将会输出u003Cu002Fpu003Eu003Cpreu003E{}u003Cbru003Etrueu003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E3、Symbol.matchu003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003ESymbol.match 在字符串使用match()方法时,为其实现自定义的逻辑。如下段代码所示:u003Cu002Fpu003Eu003Cpu003E没自定义前:u003Cu002Fpu003Eu003Cpreu003Econst re=u002Ffoou002Fu003Cbru003Econsole.log(‘bar’.match(re));u002Fu002Fnullu003Cbru003Econsole.log(‘foo’.match(re));u003Cbru003Eu002Fu002F[ ‘foo’, index: 0, input: ‘foo’, groups: undefined ]u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E使用Symbol.match后:u003Cu002Fpu003Eu003Cpreu003Econst re=u002Ffoou002Fu003Cbru003Ere[Symbol.match]=function (str) {u003Cbru003E const regexp=this;u003Cbru003E console.log(str);u003Cbru003E return true;u003Cbru003E}u003Cbru003Econsole.log(‘bar’.match(re));u003Cbru003Econsole.log(‘foo’.match(re));u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E上端代码将会输出:u003Cu002Fpu003Eu003Cpreu003Ebaru003Cbru003Etrueu003Cbru003Efoou003Cbru003Etrueu003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E4、Symbol.toPrimitiveu003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E在JS开发中,我们会利用其中的隐式转换规则,其中就包括将引用类型转换成值类型,然而有时隐式转换的结果并不是我们所期望的。虽然我们可以重写toString()方法来自定义对象在隐式转换成字符串的处理,但是如果出现需要转换成数字时变得无从入手。我们可以使用Symbol.toPrimitive来定义更灵活处理方式,如下段代码所示(仅为演示,可结合自己的业务自行修改):u003Cu002Fpu003Eu003Cpreu003Econst obj={};u003Cbru003Econsole.log(+obj);u003Cbru003Econsole.log(`${obj}`);u003Cbru003Econsole.log(obj+””);u003Cbru003Eu002Fu002Foutput:u003Cbru003Eu002Fu002FNaNu003Cbru003Eu002Fu002F[object Object]u003Cbru003Eu002Fu002F[object Object]u003Cbru003Econst transTen={u003Cbru003E [Symbol.toPrimitive](hint){u003Cbru003E switch (hint) {u003Cbru003E case ‘number’:u003Cbru003E return 10;u003Cbru003E case ‘string’:u003Cbru003E return ‘Ten’;u003Cbru003E default:u003Cbru003E return true;u003Cbru003E }u003Cbru003E }u003Cbru003E}u003Cbru003Econsole.log(+transTen);u003Cbru003Econsole.log(`${transTen}`);u003Cbru003Econsole.log(transTen+””);u003Cbru003Eu002Fu002Foutput:u003Cbru003Eu002Fu002F10u003Cbru003Eu002Fu002FTenu003Cbru003Eu002Fu002Ftrueu003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E5、Symbol.toStringTagu003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E前面的表格提到过,Symbol.toStringTag的作用就是自定义这个类的实例在调用toString()时的标签内容。u003Cu002Fpu003Eu003Cpu003E比如我们在开发中定义的类,就可以通过Symbol.toStringTag来修改toString()中的内容,利用它做为属性键为类型定一个Getter。u003Cu002Fpu003Eu003Cpreu003Eclass Foo{u003Cbru003E get [Symbol.toStringTag](){return ‘Bar’}u003Cbru003E}u003Cbru003Econst obj=new Foo();u003Cbru003Econsole.log(obj.toString());u003Cbru003Eu002Fu002Foutput:[object Bar]u003Cbru003Eu003Cu002Fpreu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fdfic-imagehandleru002F6aff4b30-8d71-40ec-9df2-23a77295ee13″ img_width=”1200″ img_height=”1168″ alt=”「ES6基础」Symbol介绍:独一无二的值” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Ch1u003Eu003Cstrongu003E小节u003Cu002Fstrongu003Eu003Cu002Fh1u003Eu003Cpu003E今天的内容有些多,需要慢慢理解,我们清楚了Symbol值是独一无二的,Symbol的一些使用场景,以及使用Symbol常用值改写更底层的方法,让我们写出更灵活的处理逻辑。Symbol虽然强大,但是用好它还需要在实践中结合业务场景进行掌握。u003Cu002Fpu003Eu003Cpu003Eu003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6713733594054918663u002F?group_id=6713733594054918663″ target=”_blank”u003E「ES6基础」let和作用域u003Cu002Fau003Eu003Cu002Fpu003Eu003Cpu003Eu003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6714091462650233352u002F?group_id=6714091462650233352″ target=”_blank”u003E「ES6基础」const简介u003Cu002Fau003Eu003Cu002Fpu003Eu003Cpu003Eu003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6714508610916844035u002F?group_id=6714508610916844035″ target=”_blank”u003E「ES6基础」默认参数值u003Cu002Fau003Eu003Cu002Fpu003Eu003Cpu003Eu003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6714847432842150414u002F?group_id=6714847432842150414″ target=”_blank”u003E「ES6基础」模板字符串(Template String)u003Cu002Fau003Eu003Cu002Fpu003Eu003Cpu003Eu003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6715214218485826059u002F?group_id=6715214218485826059″ target=”_blank”u003E「ES6基础」展开语法(Spread syntax)u003Cu002Fau003Eu003Cu002Fpu003Eu003Cpu003Eu003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6716304548283023875u002F?group_id=6716304548283023875″ target=”_blank”u003E「ES6基础」解构赋值(destructuring assignment)u003Cu002Fau003Eu003Cu002Fpu003Eu003Cpu003Eu003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6712258013375234568u002F?group_id=6712258013375234568″ target=”_blank”u003E「ES6基础」箭头函数(Arrow functions)u003Cu002Fau003Eu003Cu002Fpu003Eu003Cpu003Eu003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6721934116918428167u002F?group_id=6721934116918428167″ target=”_blank”u003E「ES6基础」Map与WeakMapu003Cu002Fau003Eu003Cu002Fpu003Eu003Cpu003Eu003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6717126750024761864u002F?group_id=6717126750024761864″ target=”_blank”u003E「ES6基础」Set 与 WeakSetu003Cu002Fau003Eu003Cu002Fpu003Eu003Cpu003Eu003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6712646837519532551u002F?group_id=6712646837519532551″ target=”_blank”u003E「ES6基础」迭代器(iterator)u003Cu002Fau003Eu003Cu002Fpu003Eu003Cpu003Eu003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6712984431553937934u002F?group_id=6712984431553937934″ target=”_blank”u003E「ES6基础」生成器(Generator)u003Cu002Fau003Eu003Cu002Fpu003Eu003Cpu003E更多精彩内容,请微信u003Cstrongu003E关注“前端达人”公众号u003Cu002Fstrongu003E!u003Cu002Fpu003Eu003Cu002Fdivu003E”

原文始发于:「ES6基础」Symbol介绍:独一无二的值

主题测试文章,只做测试使用。发布者:杀手梦三刀,转转请注明出处:http://www.cxybcw.com/10700.html

联系我们

13687733322

在线咨询:点击这里给我发消息

邮件:1877088071@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code