ES6--》一文搞懂JS新的原始数据类型—Symbol

简介: ES6引入了一种新的原始数据类型Symbol,表示独一无二的值,它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。

Symbol介绍与创建

ES6引入了一种新的原始数据类型Symbol,表示独一无二的值,它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。

Symbol特点

Symbol的值是唯一的,用来解决命名冲突问题。

Symbol值不能与其他数据进行运算。

Symbol定义的对象属性不能使用 for...in 循环遍历,但是可以使用 Reflect.ownKeys 来获取对象的所有键名。

Symbol值通过Symbol()函数生成,也就是说,对象的属性名可以有两种类型,一种就是原来就有的字符串,另一种就是新增的Symbol类型。

创建Symbol有俩种方式,Symbol和Symbol.for(),这两种方式的区别前者不能登记在全局环境中供搜索,后者却可以,所有Symbol.for()不会每次调用就返回一个新的Symbol类型值,而是先检查给定的key值是否存在,不存在才会新建一个值。

<script>// 创建Symbollets=Symbol()
console.log(s,typeofs);//Symbol() 'symbol'//Symbol()函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述//Symbol()函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。lets1=Symbol('张三')
lets2=Symbol('张三')
console.log(s1===s2);//false// 创建Symbol的另一种方法:Symbol.for() 该方法创建的字符串参数相等,Symbol也相等lets3=Symbol.for('张三')
lets4=Symbol.for('张三')
// Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key。console.log(Symbol.keyFor(s3));//张三console.log(s3===s4);//true</script>

Symbol 值不能与其他类型的值进行运算,否则会报错,但是Symbol值可以显示转换为字符串,而且Symbol也可以转为布尔值。

<script>lets=Symbol('My Symbol')
// let result = s + 100// console.log(result);//Cannot convert a Symbol value to a number// 转字符串console.log(String(s));//Symbol(My Symbol)// 转布尔值console.log(Boolean(s));//true</script>

当然如果你想直接返回 Symbol 的字符串参数的值的话,可以借用 Symbol 的实例属性:description,直接返回 Symbol 值的描述。

<script>lets=Symbol('My Symbol')
console.log(s.description);//My Symbol</script>

针对数据类型的类别可以总结以下方式:(面试官问你JS有哪几种数据类型好用到)

USONB (you are so niubility)

u:undefined

s:string、Symbol

o:object

n:null、number

b:boolean

设置Symbol属性的注意点

为了保证不会出现同名的属性,防止对象的某一个键不小心被改写或覆盖。使用作为属性名的Symbol 进行操作。设置Symbol的方式如下

注意:我们在进行设置Symbol值作为对象属性名时,是不能用点运算符,因为点运算符后面总是字符串,所以不会读取作为Symbol标识名所指代的那个值,导致Symbol的属性名实际上是一个字符串,而不是一个Symbol值,所以在对象内部使用Symbol值定义属性时,Symbol值必须放在方括号里面。

<script>lets=Symbol('My Symbol')
// 第一种leta= {}
a[s] ='hello world'// 第二种letb= {
        [s]:'hello people'    }
// 第三种letc= {}
Object.defineProperty(c,s,{value:'hello animal'})
// 以上结果都能达到相同的效果,举例console.log(c);
</script>

图片.png

Symbol属性名的遍历

如果想遍历Symbol的属性名,正常的方法是办不到的,需要使用特定的方法,有一个方法可以获取指定对象的所有键名并返回一个数组,方法为:Object.getOwnPropertySymbols()方法。

<script>letobj= {}
leta=Symbol('a')
letb=Symbol('b')
obj[a] ='hello'obj[b] ='world'constobjectSymbols=Object.getOwnPropertySymbols(obj)
console.log(objectSymbols);//[Symbol(a), Symbol(b)]</script>

上面的方法能够返回Symbol的键名,还有一个方法能够返回Symbol键名,但不只有Symbol键名而是所有的键名都被返回出来。该方法为:Reflect.ownKeys(obj)

<script>letobj= {
name:'张三',
age:18,
        [Symbol('mySymbol')]:1,
gender:'男'    }
console.log(Reflect.ownKeys(obj));//['name', 'age', 'gender', Symbol(mySymbol)]</script>

Symbol内置值

除了定义自己使用的 Symbol 值以外,ES6还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。方法如下:

Symbol.hasInstance

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

<script>classPerson {
static [Symbol.hasInstance](param){
console.log(param);
console.log('我被用来检测类型了');
//return true        }
    }
leto= {}
console.log(oinstanceofPerson);
</script>

图片.png

当出现 instanceof 时,symbol 的 hasInstance 属性就会被触发,并且可以把要判断的实例对象传进来。也就是说将 instanceof 前面的值传递到 param 形参这个方法,由它来决定返回的true还是false。说白了就是可以自己控制类型检测。

Symbol.isConcatSpreadable

对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于数组上面时Array.prototype.concat()语句,判断数组是否可以展开。false为不展开。

<script>constarr= [1,2,3]
constarr1= [4,5,6]
console.log(arr.concat(arr1));
// 将arr1设置为不展开,作为一个整体与arr进行合并arr1[Symbol.isConcatSpreadable] =falseconsole.log(arr.concat(arr1));
</script>

图片.png

类似数组的对象正好相反,默认不展开,它的 Symbol.isConcatSpreadable 属性设为 true,才能展开。

<script>letobj= {
0:'a',
1:'b',
2:'c',
length:3    }
console.log([1,2].concat(obj,'d'));
// 将该属性设置为true,进行展开obj[Symbol.isConcatSpreadable] =trueconsole.log([1,2].concat(obj,'d'));
</script>

图片.png

Symbol.unscopables

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

<script>// 将排除的键名以数组方式打印出来console.log(Object.keys(Array.prototype[Symbol.unscopables]));
</script>

图片.png

// 没有 unscopables 时classMyClass {
foo() { return1; }
}
varfoo=function () { return2; };
with (MyClass.prototype) {
foo(); // 1}
// 有 unscopables 时// 通过指定Symbol.unscopables属性,使得with语法块不会在当前作用域寻找foo属性,即foo将指向外层作用域的变量classMyClass {
foo() { return1; }
get [Symbol.unscopables]() {
return { foo: true };
  }
}
varfoo=function () { return2; };
with (MyClass.prototype) {
foo(); // 2}

Symbol.match

JavaScript中的Symbol.match属性是well-known符号,用于标识正则表达式与字符串的匹配,当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值。

<script>constreg=/hello world/reg[Symbol.match] =falseconsole.log('/hello/'.startsWith(reg));//falseconsole.log('/hello world/'.startsWith(reg));//true</script>

Symbol.replace

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

<script>constx= {};
// Symbol.replace方法会收到两个参数,第一个参数是replace方法正在作用的对象,第二个参数是替换后的值。x[Symbol.replace] = (...s) =>console.log(s); // ["Hello", "World"]'Hello'.replace(x, 'World')
</script>

Symbol.search

指定了一个搜索方法,这个方法接受用户输入的正则表达式,返回该正则表达式在字符串中匹配到的下标,这个方法由以下的方法来调用 String.prototype.search()。该属性指向一个方法,当该对象被 str.search(myObject)方法调用时,会返回该方法的返回值。

<script>classcaseInsensitiveSearch {
constructor(value) {
this.value=value.toLowerCase();
    }
    [Symbol.search](string) {
returnstring.toLowerCase().indexOf(this.value);
    }
    }
console.log('foobar'.search(newcaseInsensitiveSearch('BaR')));
// expected output: 3</script>

Symbol.split

Symbol.split 这个属性方法 指向的是一个正则表达式的索引处分割字符串的方法,这个方法通过String.prototype.split()调用;该属性指向一个方法,当该对象被 str.split(myObject)方法调用时,会返回该方法的返回值。

<script>varexp=  {
pat:'in',
        [Symbol.split](str) {
returnstr.split(this.pat);
        }
    }
// "dayinlove".split(exp)调用[Symbol.split](str)处理,并把实参"dayinlove"传给形参strconsole.log("dayinlove".split(exp));//["day", "love"]</script>

Symbol.iterator

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

<script>constmyIterable= {};
myIterable[Symbol.iterator] =function* () { //function*这种声明方式会定义一个生成器函数,它返回一个对象。yield1;
yield2;
yield3;
    };
console.log([...myIterable]);// [1, 2, 3]</script>

Symbol.toPrimitive

作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。该函数被调用时,会传递一个字符粗参数 hint ,表示要转换到的原始值的预期类型。hint参数的取值是:number、string 和 default 中的任意一个。

// 一个没有提供 Symbol.toPrimitive 属性的对象,参与运算时的输出结果varobj1= {};
console.log(+obj1);     // NaNconsole.log(`${obj1}`); // "[object Object]"console.log(obj1+""); // "[object Object]"// 接下面声明一个对象,手动赋予了 Symbol.toPrimitive 属性,再来查看输出结果varobj2= {
  [Symbol.toPrimitive](hint) {
if (hint=="number") {
return10;
    }
if (hint=="string") {
return"hello";
    }
returntrue;
  }
};
console.log(+obj2);     // 10      -- hint 参数值是 "number"console.log(`${obj2}`); // "hello" -- hint 参数值是 "string"console.log(obj2+""); // "true"  -- hint 参数值是 "default"

Symbol.toStringTag

通常作为对象的属性键使用,对应的属性值应该为字符串类型,这个字符串用来表示该对象的自定义类型标签。

<script>classPerson {
get [Symbol.toStringTag](){
return'xxx'        }
    }
letper=newPerson()
console.log(Object.prototype.toString.call(per));//[object xxx]</script>

Symbol.species

指定构造函数用于创建派生对象的函数值属性,即创建衍生对象时,会使用该属性。作用:实例对象在运行过程中,会调用该属性指定的构造函数,用来返回基类的实例而不是子类的实例。

<script>classArray1extendsArray {
staticget [Symbol.species]() { returnArray; }
    }
consta=newArray1(1, 2, 3);
constmapped=a.map(x=>x*x);
// 定义了Symbol.species属性后,导致 a.map(x => x * x) 生成的衍生对象不在是Array1的实例而是Arrayconsole.log(mappedinstanceofArray1);//falseconsole.log(mappedinstanceofArray);//true</script>


相关文章
|
2月前
|
存储 JavaScript 对象存储
js检测数据类型有那些方法
js检测数据类型有那些方法
140 59
|
12天前
|
JavaScript 前端开发 开发者
如何在 JavaScript 中处理不同类型的错误?
【10月更文挑战第29天】通过对不同类型错误的准确识别和恰当处理,可以提高JavaScript程序的可靠性和稳定性,减少错误对程序运行的影响。
|
1月前
|
JavaScript 前端开发 安全
深入理解TypeScript:增强JavaScript的类型安全性
【10月更文挑战第8天】深入理解TypeScript:增强JavaScript的类型安全性
45 0
|
11天前
|
设计模式 JavaScript 前端开发
es6加上symbol的基础数据类型
【10月更文挑战第30天】ES6 中的 `Symbol` 作为一种新的基础数据类型,为 JavaScript 提供了一种创建唯一标识符和处理对象属性名冲突的有效方式,丰富了 JavaScript 的数据类型体系和编程模式,在实际开发中具有重要的应用价值。
|
11天前
|
设计模式 JavaScript 前端开发
es6加上symbol的基础数据类型
【10月更文挑战第22天】ES6中的 `Symbol` 作为一种新的基础数据类型,为JavaScript提供了一种创建唯一标识符和处理对象属性名冲突的有效方式,丰富了JavaScript的数据类型体系和编程模式,在实际开发中具有重要的应用价值。
|
11天前
|
JavaScript 前端开发 Java
除了 JavaScript,还有哪些编程语言支持 Set 类型
【10月更文挑战第30天】这些编程语言中的 `Set` 类型虽然在语法和具体实现细节上有所不同,但都提供了类似的集合操作功能,方便开发者在不同的编程场景中处理集合相关的数据和逻辑。
|
12天前
|
存储 JavaScript 前端开发
js的基础类型和引用类型
【10月更文挑战第29天】理解 JavaScript 中的基础类型和引用类型的区别对于正确地编写代码和理解程序的行为非常重要。在实际开发中,需要根据具体的需求合理地选择和使用不同的数据类型,以避免出现一些意想不到的错误和问题。同时,在处理引用类型数据时,要特别注意对象的引用关系,避免因共享引用而导致的数据不一致等问题。
|
29天前
|
存储 JavaScript 前端开发
JavaScript 数据类型详解:基本类型与引用类型的区别及其检测方法
JavaScript 数据类型分为基本数据类型和引用数据类型。基本数据类型(如 string、number 等)具有不可变性,按值访问,存储在栈内存中。引用数据类型(如 Object、Array 等)存储在堆内存中,按引用访问,值是可变的。本文深入探讨了这两种数据类型的特性、存储方式、以及检测数据类型的两种常用方法——typeof 和 instanceof,帮助开发者更好地理解 JavaScript 内存模型和类型检测机制。
67 0
JavaScript 数据类型详解:基本类型与引用类型的区别及其检测方法
|
1月前
|
JavaScript 前端开发 开发者
【干货拿走】JavaScript中最全的数据类型判断方法!!!!
【干货拿走】JavaScript中最全的数据类型判断方法!!!!
22 1
|
30天前
|
存储 JavaScript 前端开发
JavaScript数据类型全解:编写通用函数,精准判断各种数据类型
JavaScript数据类型全解:编写通用函数,精准判断各种数据类型
18 0