ES6新增数据类型(Symbol)
基本(原始)类型和引用类型介绍
在了解Symbol之前,我们需要了解下JS的数据类型,在JS中数据类型分为两类:基本(原始)类型和引用类型。
- 基本(原始)类型:数值型(Number),字符类型(String),布尔值型(Boolean),null 和 underfined
- 引用类型:对象(Object)
那es6新增的Symbol是什么类型呢? 这里Symbol也是基本类型;
概述
ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。
let syb1 = Symbol();
let syb2 = Symbol();
console.log(syb1) // Symbol()
console.log(typeof syb1) // 'symbol'
console.log(syb1 == syb2) // false
console.log(syb1 === syb2) // false
由此可见,即使Symbol的描述值参数相同,它们的值也不相同,描述值仅仅是起描述的作用,不会对Symbol值本身起到任何的改变。关于描述值需要注意的一点:接受除Symbol值以外所有的值
let s1 = Symbol('foo');
let s2 = Symbol('bar');
let s3 = Symbol(3.6);
let s4 = Symbol({foo:'bar'});
console.log(s1) // Symbol(foo)
console.log(s2) // Symbol(bar)
console.log(s1.toString()) // "Symbol(foo)"
console.log(s2.toString() )// "Symbol(bar)"
console.log(s3) //Symbol(3.6)
console.log(s4) //Symbol([object Object])
为什么Symbol是基本(值)类型,而不是引用类型。Symbol函数并不是构造函数,因此不能使用new方法来生成一个Symbol对象,否则编译器会抛出异常,如执行下段代码所示:
new Symbol //TypeError: Symbol is not a constructor
- Symbol 值不能与其他类型的值进行运算,会报错
- symbol 得到的符号永远不会相等,不管符号名是否相同
- Symbol 值可以显式转为字符串、也可以转为布尔值,但是不能转为数值
- 在ES2019中增加了一个description可用于读取Symbol的描述.
description
作为属性名
由于每一个 Symbol 的值都是不相等的,所以 Symbol 作为对象的属性名,可以保证属性不重名。
const syb1 = Symbol("即将用于对象的属性名");
const obj = {
a : 1,
b : 2,
[syb1] : 3
}
console.log(obj[syb1]) //3
- Symbol 作为对象属性名时不能用.运算符,要用方括号
- Symbol 值作为属性名时,该属性是公有属性不是私有属性,可以在类的外部访问
属性名的遍历
Symbol 作为属性名不会被遍历的几种方法:
- for…in、for…of循环中
- Object.keys()
- Object.getOwnPropertyNames()
Symbol作为属性名可以被查询的:
-
Object.getOwnPropertySymbols()
该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值
定义一个私有方法
const Hero = ( () =>{
const getli = Symbol(); //方法名
return class Hero{
constructor(gong,fang,hp){
this.gong = gong;
this.fang = fang;
this.hp = hp;
}
getgong(){
console.log(this.gong * this.getli(0.8,1.1))
}
[getli](min,max){
return Math.random() * (max - min) + min;
}
}
} )()
const hero = new Hero(50,10,1000);
console.log(hero) //Hero {gong: 50, fang: 10, hp: 1000}
Symbol.for(),Symbol.keyFor()
- Symbol.for(): 重新使用同一个 Symbol 值
它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局
let syb1 = Symbol.for('foo');
let syb2 = Symbol.for('foo');
syb1 === syb2 // true
- Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key
let syb1 = Symbol.for("foo");
Symbol.keyFor(syb1) // "foo"
let syb2 = Symbol("foo");
Symbol.keyFor(syb2) // undefined
知名符号(特殊的共享符号)
- Symbol.hasInstance 可以去影响instanceof的值,该方法会因为instanceof语句的使用而被调用,来检查一个对象是否是某一个类的实例。
function A() {}
const a = new A();
console.log(a instanceof A); //true
console.log(A[Symbol.hasInstance](a)); //true
function A() {}
const a = new A();
Object.defineProperty(A,Symbol.hasInstance, {
value : function(){
return false;
}
})
console.log(a instanceof A); //false
console.log(A[Symbol.hasInstance](a)); //false
- Symbol.isConcatSpreadable 可以去配置数组的concat方法以什么方式拼接,用于为对象定义一个属性
const arr1 = [1,2,3];
const arr2 = [4,5,6];
arr2[Symbol.isConcatSpreadable] = false;
const arr3 = arr1.concat(arr2);
console.log(arr3) // [1, 2, 3, [4,5,6]]
- Symbol.toPrimitive 该方法会在该对象需要转换为值类型的时候被调用,可以根据程序的行为决定该对象需要被转换成的值。
const obj = {
a: 1,
b: 2
}
// obj[Symbol.toPrimitive] = function() {
// return 100;
// }
console.log(obj + 123);
console.log(obj * 123);
class Temperature {
constructor(degree) {
this.degree = degree;
}
[Symbol.toPrimitive](type) {
console.log(type)
if (type === "default") {
return this.degree + "摄氏度";
} else if (type === "number") {
return this.degree;
} else if (type === "string") {
return this.degree + "℃"
}
}
}
const t = new Temperature(30);
// console.log(t + 1)
console.log(String(t))
- Symbol.toStringTag 该知名符号会影响Object.prototype.toString 的返回值
class A{
[Symbol.toStringTag] = 'hello'
}
const a = new A();
console.log(a); //A {Symbol(Symbol.toStringTag): "hello"}
console.log(Object.prototype.toString.call(a)); //[object hello]