JavaScript中一种全新的数据类型-symbol
连续连载了几篇《ES6对xxx的扩展》,本节咱们换换口味,介绍一种全新的数据类型:Symbol,中文意思为:标志,记号。音标:[ˈsɪmbəl]。
数据类型
在介绍Symbol之前,我们简单介绍一下JavaScript的数据类型:
JavaScript有6中数据类型,分别是:
String 字符串类型
Number 数字类型
Object 对象类型
Boolean 布尔值类型
Null 空值
Undefined 未定义
这6种类型写过代码的同学都不会陌生,它们都有各自的用途。而ES6给我们带来一种全新的数据类型:Symbol。
每一种全新的事物的诞生都是为了解决某种问题。
设计初衷
为了探索它的设计初衷,我们聊聊一个实际的开发场景:
在一个多人合作的团队中,程序员A写了一个对象Object供其他人使用,有一天程序员B使用了这个对象Object,还为它添加了几个新的属性和方法,一切都那么顺利地完成了。
次日,测试告诉A产品有bug,A:“怎么可能,昨天还好好的,我都没改过任何东西啊~~~”。
无可奈何的A只要慢慢排查,最后发现,是B给对象Object添加方法的时候,其中一个方法名和A写的一个方法名相同,被覆盖了。
对象的属性被覆盖,这在日常开发中,也时常会出现,为了根本上解决命名问题,我们需要给属性或者方法起一个独一无二的名称,这样,才能从根本上防止属性名冲突的问题。
这就是ES6设计出一个Symbol的初衷:解决对象的属性名冲突。既然我们知道了Symbol的设计初衷,也就是知道了它的作用。接下来,我们来看看它是什么使用的:
//定义一个symbol类型的变量
let sm \= Symbol(); console.log(sm);
//打印结果:Symbol() console.log(typeof sm);
//打印结果:symbol
从上面代码案例看到,我们用一个Symbol( )函数来创建一个symbol类型的变量,我们打印了一下变量sm,得到的结果是控制台输出:Symbol( ),它代表着一个独一无二的值,虽然我们看不到它长什么样子,但基本上,它有点类似字符串。
接着,我们用typeof来检测一下变量sm的类型,得到的结果是:symbol。
怎样判断是它是独一无二的值呢?我们来看看:
let sm1 \= Symbol();
let sm2 \= Symbol(); sm1 \=== sm2 //结果:false console.log(sm1);//结果:Symbol()
console.log(sm2);//结果:Symbol()
我们定义两个symbol类型的变量sm1,sm2,然后用全等符号===(也称严格相等,第九节讲解过)进行比较,得到的是false。也就是他们都是独一无二的值,并不相等。
接着,我们分别打印两个变量,控制台输出的都是Symbol( ),看起来长得一模一样,实际是不相等的。
两个不一样的值,控制台输出的一样,这样无疑给我们开发调试带来一定的不便,有没有办法让他们看起来不一样呢?
有的,Symbo( )函数接受参数,用于对实例值的描述。我们试试看:
  let sm1 \= Symbol('sm1');
    let sm2 \= Symbol('sm2');  
    console.log(sm1);
    //结果:Symbol(sm1)
    console.log(sm2);
    //结果:Symbol(sm2)
用字符串sm1和sm2作为参数,结果打印出来的变量sm1和sm2就是Symbol(sm1)和Symbol(sm2),等于加上了描述,很容易区分出来。
需要注意的是,即使参数一样,描述一样,得到的两个值也是不相等的,不信我们来看看:
let sm1 \= Symbol('sm');
    let sm2 \= Symbol('sm');  
    sm1 \=== sm2 //结果:false
即使两个变量的描述都是“sm”,但是终究对应的值还是不一样的,symbol永远都是独一无二的值,谨记。
了解了这几个symbol类型值的特点后,前面说到,Symbol是为了解决对象属性名冲突的问题,那么我们就结合对象,来学习:
let name \= Symbol();
let person \= {
\[name\]:"张三"
}; console.log(person\[name\]);
//结果:张三 console.log(person.name);
//结果:undefined
看代码,从上往下撸,首先,我们定义一个symbol类型的变量name,它作为一个对象person的属性,对应的值是“张三”;
接着,我们用两种方式获取name的值,第一种用中括号的形式[ name ]能正确获取到,第二种用点运算符的形式,获取失败。原因是:当symbol值作为对象的属性名的时候,不能用点运算符获取对应的值。
此外还有一点要注意,把一个symbol类型的值作为对象的属性名的时候,一定要用中括号[ ],不能用点运算符,因为用点运算符的话,会导致javascript把后面的属性名为理解为一个字符串类型,而不是symbol类型。具体看代码:
let name \= Symbol();
let person \= {}; person.name \= "张三"; person\[name\]; //结果:undefined
person\['name'\]; //结果:张三
person.name; //结果:张三
其中变量name是symbol,但是给person对象设置属性的时候,用的是点运算符person.name,而不是中括号person[ name ],这会有什么后果呢?这就会导致person对象中的属性name实际上是字符串类型的,这也就解释了最后三行代码的打印结果了。
person[ name ]这句代码相当于要求javascript去person对象内找一个symbol类型的属性name,不好意思,没有,找不到。person对象只有一个字符串类型的属性name;所以,如果用person[‘name’]或者peroson.name获取的话,就能找到对应的属性name了。
原来用symbol类型的值作为对象的属性也有这么多讲究,好吧,我认了!谁叫你是ECMAScript呢,你说了算!
用symbol类型的属性除了能保证是独一无二的值,还有什么其他的特点吗?
属性名的遍历
当symbol类型的值作为属性名的时候,该属性是不会出现在for...in和for...of中的,也不会被Object.keys( )获取到。我们来看案例:
//定义一个symbol类型的变量name
let name \= Symbol(); //定义一个含有两种类型属性的对象
let person \= {
\[name\]:"张三", //symbol类型
"age":12 //string类型
}; Object.keys(person);//结果:\["age"\] for(let key in person){
console.log(key);
} //打印结果:age
person对象有两个属性,属性名有两种类型:symbol类型和string字符串类型,我们通过keys( )函数获取到的属性,只有属性age,我们通过for...in循环打印出来,也只打印出了属性age。(for...of也属于ES6的新增知识,后面会专门有一节介绍),以上几种方法都无法获取到symbol类型的属性。
getOwnPropertySymbols( )函数
如果我们硬是想要获取symbol类型的属性怎么办?我们可以用一个方法:Object.getOwnPropertySymbols( ),它会找到symbol类型的属性并且返回一个数组,数组的成员就是symbol类型的属性值,看代码:
//定义两个symbol类型的变量name,age
let name \= Symbol("name");
let age \= Symbol("age"); let person \= {
\[name\]:"张三", //symbol类型
\[age\]:12 //symbol类型
}; Object.getOwnPropertySymbols(person);
//结果:\[Symbol(name), Symbol(age)\]
person对象的两个属性都是symbol类型的,我们也知道用Object.keys( )和for...in都无法获取到它,我们就用getOwnPropertySymbols( )方法来,结果成功了,得到一个数组,数组的内容就是两个symbol类型变量对应的值Symbol(name)和 Symbol(age)。
Reflect.ownKeys( )函数
这样的话,获取字符串类型的属性和获取symbol类型的属性要分开两种不同的方式来获取,难免有有时候会很不方便,有木有什么办法让我们一次性获取所有类型的属性,不管它是字符串类型还是symbol类型呢?
有的,我们可以用Reflect.ownKeys( )方法实现:
//定义一个对象,含有两种类型的属性
    let person \= {
        \[Symbol('name')\]:"张三",
        "age": 21
    };  
    Reflect.ownKeys(person);
    //结果:\["age",Symbol(name)\]
上面的代码中,我们先定义一个对象person,它含有两个属性,一个是symbol类型的,一个是字符串类型的。
接着,我们将对象person传入Reflect.ownKeys( )函数中,函数就会给我们返回一个数组,数组的内容便是对象的属性,包括symbol类型和字符串类型。
此外,Symbol还提供了两个很实用的函数,我们来学习一下。
Symbol.for( )函数
函数作用:根据参数名,去全局环境中搜索是否有以该参数为名的symbol值,有就返回它,没有就以该参数名来创建一个新的symbol值。
文字描述总是那么乏力,所以要加上案例:
 letn1 \= Symbol.for('name');
    letn2 \= Symbol.for('name');
    console.log(n1 \=\=\= n2);
    //结果:true
上面最后一句代码,我们用全相等来对两个变量进行对比,得到:true;说明n2就是n1,两者相等。
但是细心地同学会注意到,上面的代码中,定义两个symbol值得时候用的都是Symbol.for( ),而不是用Symbol( )。
两者在创建symbol值的时候有什么不同吗?它们的区别是:Symbol.for( )创建的symbol值会被登记在全局环境中,供以后用Symbol.for( )来搜索,而Symbol( )创建的变量就没有这样的效果了。
也就是说,用Symbol( )创建的symbol值,以后用Symbol.for( )去搜索,是找不到的。不信,我们来演示一下,还是用上面的代码,我们稍微改一下第一行:
    let n1 \= Symbol('name');
    let n2 \= Symbol.for('name');
    console.log(n1 \=\=\= n2);
    //结果:false
第一行我们用Symbol( )来创建的一个symbol值,按照上述的所说的,它不会被登记在全局环境中;所以,第二行我们用Symbol.for( )去找的时候,是找不到的,找不到怎么办?此时Symbol.for( )会自动创建一个新的symbol值,也就是说n1,n2是不同的两个symbol值了,所以进行全相等比较的时候,会返回:false。
Symbol.keyFor( )函数
函数作用:返回一个以被登记在全局环境中的symbol值的key,没有就返回undefined。注意这句话的一个关键词:“被登记在全局环境中”,也就是说这个symbol值是被Symbol.for( )创建的,不是被Symbol( )创建的。
    let n1 \= Symbol.for('name');
    Symbol.KeyFor(n1);
    //结果:name
上面的变量n1是被Symbol.for( )创建,不是被Symbol( )创建的,所以用Symbol.keyFor( )去找,是能找到的,会返回这个symbol值的key,也就是它的描述:name。
我们再对上面的案例稍做修改:
    let n1 \= Symbol('name');
    Symbol.KeyFor(n1);
    //结果:undefined
这段代码的变量n1是用Symbol( )创建的,最后的结果是undefined;这就证明了两个知识点:1、Symbol( )创建symbol值不会被登记在全局环境中供Symbol.for( )和Symbol.keyFor( )搜索;2、Symbol.keyFor( )函数在全局环境中找不到对应的symbol,就回返回undefined。
以上就是ES6给我们带来的第七种数据类型:Symbol;Symbol还有更多的小知识,初学者或者新手只要掌握理解上面的几点就足够日常使用了,只要进了门,往后的深入都是自然而然的,任何知识的学习都一样。
本节小结
总结:JavaScript有了第七种数据类型:Symbol,创建一个独一无二的值;它用于对象的属性,设计初衷是为了避免对象属性冲突的问题。要获取对象symbol类型的属性,要用Object.getOwnPropertySymbols( );还提供了Symbol.for( )和Symbol.keyFor( )方法用于搜索对应的symbol值。
更多学习内容和干货请参考我的视频-我的空间****
JavaScript中一种全新的数据类型-symbol的更多相关文章
- [js]javascript中4种异步
		
javascript中4种异步: 1.ajax 2.定时器 3.事件绑定 4,回调 定时器 //顺序执行 /* var s = 0; for (var i = 0; i < 10000; i++ ...
 - JavaScript中两种类型的全局对象/函数【转】
		
Snandy Stop, thinking is the essence of progress. JavaScript中两种类型的全局对象/函数 这里所说的JavaScript指浏览器环境中的包括宿 ...
 - javascript中几种this指向问题
		
javascript中几种this指向问题 首先必须要说的是,this 永远指向函数运行时所在的对象,而不是函数被创建时所在的对象. (1).作为函数名调用 函数作为全局对象调用,this指向 ...
 - JavaScript中四种不同的属性检测方式比较
		
JavaScript中四种不同的属性检测方式比较 1. 用in方法 var o = {x:1}; "x" in o; //true "y" in o; //fa ...
 - javascript中6种基本数据类型详解
		
javascript中有5中数据类型(也称为基本数据类型):Undefined.Null.Boolean.Number和String,还有一种复杂数据类型——object,object本质是由一组键值 ...
 - JavaScript中七种数据类型·中·一
		
Standing on Shoulders of Giants; 说到JavaScript里的类型很容易就让人想起 42和"42",分别是string型和number型,但是他们可 ...
 - javascript中五种基本数据类型
		
前言: JavaScript中有五种基本数据类型(也叫做简单数据类型)分别为:undefined.null.bolean.number.string:另外还含有一种复杂的数据类型:object. 深入 ...
 - JavaScript 中 4 种常见的内存泄露陷阱
		
了解 JavaScript 的内存泄露和解决方式! 在这篇文章中我们将要探索客户端 JavaScript 代码中常见的一些内存泄漏的情况,并且学习如何使用 Chrome 的开发工具来发现他们.读一读吧 ...
 - python中几种常用的数据类型
		
1.字典 字典的创建: dict1=dict((('name','PIG'),)),其中第一层()代表里面的内容是dict函数的输入参数.第二层和第三层代表字典中的各元素,也就是key和value组合 ...
 
随机推荐
- 一篇让你明白什么是浏览器BOM方法的笔记
			
BOM Browser Object Model 浏览器对象模型 虚拟机 ,任何语言编辑的程序都需要一个虚拟机来执行.如果脱离这个环境就无法运行. 浏览器就是一种虚拟机.用来解析html语言 同一款浏 ...
 - 1.Metasploit介绍与基本命令
			
Metasploit体系框架介绍 Metasploit是目前世界上领先的渗透测试工具,也是信息安全与渗透测试领域最大的开源项目之一.它彻底改变了我们执行安全测试的方式. Metasploit之所以流行 ...
 - 实验十一 MySQLl备份与恢复1
			
实验十一 MySQL备份与恢复 一. 实验内容: 1. 使用SQL语句导入和导出表数据 2. 使用客户端工具备份还原数据库 3. 使用日志文件恢复数据库 二. 实验项目:学生成绩数据库 创建用于学 ...
 - Linux 《conky配置说明书》
			
名称 conky - 最初基于躯干代码的X系统监视器,但更多的kickass.它只是继续给予它.是啊. 概要 conky [ options ] 描述 Conky是最初基于torsmo的X系统监视器. ...
 - Java 程序该怎么优化?(工具篇)
			
程序员:为什么程序总是那么慢?时间都花到哪里去了? 面试官:若你写的 Java 程序,出现了性能问题,该怎么去排查呢? 工欲善其事必先利其器,为你呈上一箩筐性能优化工具,必有一款满足你,废话不多说,直 ...
 - 通俗易懂.NET GC垃圾回收机制(适用于小白面试,大牛勿喷)
			
情景:你接到xx公司面试邀请,你怀着激动忐忑的心坐在对方公司会议室,想着等会的技术面试.技术总监此时走来,与你简单交谈后.... 技术:你对GC垃圾回收机制了解的怎么样? 你:还行,有简单了解过. 技 ...
 - javascript 3d网页 示例 ( three.js 初探 七)
			
1 完整代码下载 https://pan.baidu.com/s/1JJyVcP2KqXsd5G6eaYpgHQ 提取码 3fzt (压缩包名: 2020-4-5-demo.zip) 2 图片展示 3 ...
 - echarts整理
			
保存一些常用的echarts图表及制作方法
 - SciPy - 正态性 与 KS 检验
			
假设检验的基本思想 若对总体的某个假设是真实的,那么不利于或者不能支持这一假设的事件A在一次试验中是几乎不可能发生的:如果事件A真的发生了,则有理由怀疑这一假设的真实性,从而拒绝该假设: 假设检验实质 ...
 - Shiro 笔记
			
功能 认证 授权 加密 session 管理 认证 Subject 是一个与系统交互的实体,可以是人,也可以是其他等 调用 SecurityUtils.getSubject()返回当前Subject, ...