ES6学习之路~~Symbol:独一无二的值类型
- Symbol是什么呢?先看下面这个面试题
1. js有多少种数据类型?
- 同学们异口同声的回答:6种。
- 那对不对呢?在ES5及以前,是对的。但是,注意啊,现在已经是ES6正式发布两年后了,要回答7种!
- 至于除了:undefined、null、string、number、boolean、object这六种之外的第七种呢,就是这节我要详细述说的symbol类型了。
- 我们先来验证下,在谷歌控制台输入下面的代码看看:
let s = Symbol();
console.log(s); // 打印 Symbol()
typeof s; // 数据类型为 "symbol"
Symbol数据类型是怎么申明的?
- 先不管这个数据类型有什么用(既然能通过ES6,就不用质疑其作用啦),先来看看怎么才能用出来(在支持ES6,例如谷歌控制台运行下面的代码)
let s1 = value; // 只能申明string,number,boolean,object类型的数据
let s2; // 申明值为undefined的数据,未赋值前为undefined类型,赋值后,变量类型根据值类型改变
let s3 = null; // 申明值为null的数据
<!-- 以上,常见的申明方式并不能申明出symbol类型 -->
let sym = Symbol(); // symbol类型只能通过Symbol()函数生成
let sym1 = Symbol();
let sym3 = Symbol(s1); // Symbol()函数的参数只作为控制台打印时候区分作用(不传参的symbol型数据打印在控制台都返回symbol()),无其他含义
<!-- symbol值比较 -->
console.log(sym == sym1); // false
<!-- symbol型变量赋值 -->
let ev = '';
typeof ev; // "string"
ev = sym1;
console.log(ev, ' / ', typeof ev); // Symbol() / "symbol"
console.log()
ev + 11; // TypeError
ev + 'aa'; // TypeError
let symStr = sym3.toString(); // 可以使用toString()方法转换为字符串
console.log(String(sym3)); // 可以强转为String型数值
console.log(Boolean(sym3)); // 可以强转为Boolean型数值
- 申明很简单,通过Symbol()函数生成即可,并且生成的数据是绝对不等于除自己外的任何一个Symbol值
Symbol类型数据的特点
- 从上面的代码,可以看出:
- symbol值 有自己的数据类型
- symbol值 绝对不等于除自己外的任何一个Symbol值,即symbol值是独一无二的
- symbol值 不能直接做数值相加和字符串拼接等
- symbol值 可以强转为String型和Boolean型的值
- 根据这些特点,我们再来讨论下Symbol值的作用吧
Symbol类型数据的作用
- 作为对象属性名,可以保证不会出现同名的对象属性,能防止耨个键被不小心改写或覆盖。symbol值作为对象的属性名使用时,必须放在[]内部(ES6中,增强的对象属性写法),不放在方括号中的写法只适用于字符串属性名
var symKey = Sym();
<!-- 第一种写法 -->
var a = {};
a[symKey] = 'hello';
<!-- 第二种写法 -->
var a = {
[symKey]: 'hello'
}
<!-- 第三种写法 -->
var a = {};
Object.defineProperty(a, symKey, { value: 'hello' });
<!-- 以上写法,得到相同的结果 -->
a[symKey]; // 'hello'
<!-- 不能写成点属性名的形式 -->
var a = {};
a.synKey = 'hello';
a[symKey]; // undefined
a['symKey']; // 'hello',因为 对象.属性名 的形式只适用于字符串属性名
- symbol作为属性名的对象属性名的遍历
- symbol值属性名在遍历对象时,不会出现在for…in、for…of循环中(只能遍历字符串类型的属性名称),但symbol值的属性也不是私有的属性,有一个Object.getOwnPropertySymbols(obj)方法返回一个数组,成员是当前对象的所有Symbol值的属性名
var a = Symbol('a');
var b = Symbol('b');
var objSym = {
[a]: 'aaa',
[b]: 'bbb',
c: 'ccc',
d: 'ddd'
}
var symPorpertys = Object.getOwnPropertySymbols(objSym);
console.log(symPorpertys); // [Symbol(a), Symbol(b)]
for(let ii in objSym) {
console.log(ii); // c 、 d
}
- 那,能不能有个方法可以返回所有的键名呢?当然是有的,Reflect.ownKeys(obj)方法
var a = Symbol('a');
var b = Symbol('b');
var objSym = {
[a]: 'aaa',
[b]: 'bbb',
c: 'ccc',
d: 'ddd'
}
console.log(Reflect.ownKeys(objSym));
<!-- 遍历对象所有属性名 -->
for(let ii in Reflect.ownKeys(objSym)) {
console.log('属性名:'+ Reflect.ownKeys(objSym)[ii]);
}
<!-- 下面在讨论便利属性值 -->
- 以symbol值作为属性名的属性不会被常规方法遍历得到,因此可以利用这个特性为对象定义一些非私有但又只希望只用于内部的方法
怎么根据symbol(‘xxx’);去找有没有对应的symbol值?这里引入一个新的API:
- Symbol.for(),返回值为一个symbol值,同Symbol()方法,不同之处在于已存在的Symbol值使用Symbol.for()不会产生新的Symbol值,而是返回之前存在的Symbol值,而Symbol()每次都返回完全不同的Symbol值
var ss1 = Symbol('ss');
var ss2 = Symbol('ss');
ss1 === ss2; // false
var sf1 = Symbol.for('sf');
var sf2 = Symbol.for('sf');
sf1 === sf2; // true
- Symbol.keyFor(‘xxx’)方法返回一个Symbol.for(‘xxx’)方法申明的Symbol的key,用于Symbol()申明的Symbol值,则返回undefined
var s1 = Symbol('s');
var s2 = Symbol.for('s');
Symbol.keyFor(s1); // undefined
Symbol.keyFor(s2); // s
- Symbol.for()为Symbol登记的环境为全局环境,可以在不同的iframe标签中被Symbol.keyFor()得到
来源:CSDN
作者:xeanyee
链接:https://blog.csdn.net/github_38847071/article/details/78275173