当前位置: 首页 > Web前端 > JavaScript

Symbol详解

时间:2023-03-26 23:53:24 JavaScript

SymbolSymbol是es6引入的一种新的原始数据类型,是一个唯一值。至此,js的数据类型如下:数据类型说明undefinedundefinednullnullbooleanBooleanvaluestringstringnumbernumberBigintlargeintegerObjectobjectSymbolSymbolSymbol由Symbol()函数生成。除了字符串,对象的属性名称现在可以使用新添加的Symbol类型。如果属性名使用Symbol,那么它是唯一的,不会与其他属性名冲突。让s=Symbol()console.log(typeofs);//Symbol注意:Symbol()函数前不能使用new,否则会报错。因为生成的Symbol是原始类型的值,不是对象,所以不能用new调用。而且Symbol的值不是对象,不能给Symbol加上属性。可以理解为Symbol是一种类似于string的数据类型。Symbol接收一个字符串作为参数,代表对Symbol的描述,添加描述可以用来区分多个Symbol。让s2=Symbol('desc')让s3=Symbol('desc2')console.log(s2);//符号(desc)console.log(s3);//Symbol(desc2)如果传入的Symbol参数是对象,需要将对象转成字符串再生成Symbol,否则会显示[objectObject]。letobj={name:'东方无敌'}lets4=Symbol(JSON.stringify(obj))console.log(s4);//Symbol({"name":"东方无敌"})lets5=Symbol(obj)console.log(s5);//Symbol([objectObject])Symbol传入的参数只是描述,在事实上Symbol和Symbol并不相等。让sy=Symbol()让sy2=Symbol()console.log(sy===s2);//falseletsy3=Symbol('a')letsy4=Symbol('a')console.log(sy3===sy4);//false每次调用Symbol()都会产生一个唯一的值,每个Symbol都不相等。符号值不能参与对其他类型值的运算,否则会报错。让a=Symbol('hello')console.log(a+'world');//错误CannotconvertaSymbolvaluetoastringSymbolconversioncanbeconvertedtostringleta2=Symbol('hello')console.log(String(a2));//Symbol(hello)如果需要返回Symbol的描述,需要使用es2019提供的Symbol实例属性description来返回描述。leta2=Symbol('hello')console.log(a2.description);//helloSymbol可以转换为布尔值(boolean)leta2=Symbol('hello')console.log(Boolean(a2));//trueconsole.log(Boolean(!a2));//falseSymbol属性名Symbol作为属性名letn=Symbol()//方法一letobj2={[n]:'东方无敌'}console.log(obj2);//{Symbol():'东方不败'}console.log(obj2[n]);//东方无敌//方法二obj2[n]='东方乞丐'console.log(obj2[n]]);//东方求败//方法三letobj3={}letback=Object.defineProperty(obj3,n,{value:'IntroductiontoArt'})console.log(obj3[n]);//ArtObject.defineProperty指令介绍第一个参数:要在其上定义属性的对象第二个参数:要定义或修改的属性的名称第三个参数:属性描述符要定义或修改的符号值修饰为对象使用属性名时,不能使用点运算符获取Symbol属性。使用点运算符相当于给对象添加一个字符串属性名,而不是获取Symbol。letn2=Symbol()letobj4={}console.log(obj4.n2='中国工艺美术史');//中国工艺美术史console.log(obj4[n2]);//undefinedconsole.log(obj4);//{n2:'中国工艺美术史'}属性名遍历Symbol不可枚举,Symbol作为对象键名不可遍历,for...in,Object.keys等方法必须Symbol键名未找到,并且JSON.stringify()不会返回Symbol。letm=Symbol('a')letf={[m]:'东方不败',name:'西方乞讨',name2:'光合作用'}//西方乞讨,光合作用for(kinf){console.日志(f[k]);}console.log(Object.keys(f));//['name','name2']console.log(JSON.stringify(f));//{"name":"西求败","name2":"光合作用"}Reflect.ownKeys()可以返回正则键名和Symbol键名console.log(Reflect.ownKeys(f));//['name','name2',Symbol(a)]Object.getOwnPropertySymbols()仅返回Symbol属性console.log(Object.getOwnPropertySymbols(f));//[Symbol(a)]Symbol.for(),Symbol.keyFor()Symbol.for()Symbol有个特点就是Symbol不等于Sombol,但是有时候我们需要相同的Symbol值letr=Symbol.for('a')letr2=Symbol.for('a')控制台。日志(r===r2);//trueSymbol.for()和Symbol()都会生成新的Symbols,前者会注册到全局环境中提供搜索,后者不会。Symbol.for()每次调用都会先检查参数key是否存在,如果不存在则创建一个新的value。Symbol()每次被调用时都会创建一个新值。Symbol.keyFor()Symbol.keyFor()返回注册的Symbol值的keyletr3=Symbol.for('b')letr4=Symbol('c')console.log(Symbol.keyFor(r3));//bconsole.log(Symbol.keyFor(r4));//undefinedSymbol内置值Symbol.hasInstanceSymbol.hasInstance用于判断对象是否为构造函数实例classmyClass{static[Symbol.hasInstance](val){returntypeofval==='number'}//static[Symbol.hasInstance](val){//返回类型val==='boolean'//}}console.log(100instanceofmyClass);//trueconsole.log('100'instanceofmyClass);//false多个Symbol.hasInstance会被覆盖,只保留最下面的一个。Symbol.isConcatSpreadableSymbol.isConcatSpreadable用来表示Array.prototype.concat()是否可以展开,true和undefined可以展开,false不能展开。让arr1=[1,2]让arr2=[3,4]console.log(arr1[Symbol.isConcatSpreadable]);//undefinedconsole.log(arr1.concat(arr2));//[1,2,3,4]console.log(arr1[Symbol.isConcatSpreadable]=false)console.log(arr1.concat(arr2));//[[1,2],3,4]Symbol.species对象的Symbol.species属性指向一个构造函数,创建派生对象时会用到//这里继承了Array类的原型MyArrayextendsArray{}leta=newMyArray(1,2,3)letb=a.map(el=>el+1)console.log(b);//constructor:classMyArrayb和c调用数组方法,所以它们应该是Array的实例,但实际上它们也是MyArray的实例classMyArrayextendsArray{staticget[Symbol.species](){returnArray}}leta=newMyArray(1,2,3)letb=a.map(el=>el+1)letc=a.filter(el=>el==2)console.log(a,b,c);//1,2,32,3,42console.log(binstanceofMyArray);//falseconsole.log(b);//constructor:classMyArraySymbol.species可以在创建派生对象时将此属性返回的函数用作构造函数中找到。这里返回的是Array,所以创建的派生对象使用Array作为构造函数,而不是MyArray。如果这里返回的是String,上面的map和filter会报错,因为派生对象使用String作为构造函数,而String没有数组方法。Symbol.matchSymbol.match指向一个函数。如果函数存在,则调用并返回方法classMyMatch{[Symbol.match](val){return'helloworld'.indexOf(val)}}//匹配字符串方法的返回值在字符串中指定值并返回console.log('e'.match(newMyMatch()));//1案例源码:https://gitee.com/wang_fan_w/es6-science-institute如果您觉得本文对您有帮助,请点亮star