连续连载了几篇《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值。

文字描述总是那么乏力,所以要加上案例:

let n1 = Symbol.for('name');
    let n2 = 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相关推荐

  1. 第六节:又一种新的数据类型:元组Tuple

    每次发布招聘推文都会被喷薪资太低,招不到人.上周的发布react开发的招聘,居然没有人喷薪资太低了,突然有点不习惯. 摊手+无辜脸.jpg 招聘先放一边,继续回来学习我们的typescript,后续简 ...

  2. 大白话5分钟带你走进人工智能-第十一节梯度下降之手动实现梯度下降和随机梯度下降的代码(6)...

                                第十一节梯度下降之手动实现梯度下降和随机梯度下降的代码(6) 我们回忆一下,之前咱们讲什么了?梯度下降,那么梯度下降是一种什么算法呢?函数最优化 ...

  3. turtle 函数 方法_学python第十一节:turtle深入 了解

    学python第十一节:深入分析turtle Turtle是一个直观有趣的图形绘制函数. 这节课对turtle的以下几点进行补充: 在蟒蛇绘制代码中提到过import 库引用保留字的函数,是补充pyt ...

  4. Kotlin学习笔记 第二章 类与对象 第十一节 枚举类 第八节密封类

    参考链接 Kotlin官方文档 https://kotlinlang.org/docs/home.html 中文网站 https://www.kotlincn.net/docs/reference/p ...

  5. 第三百九十一节,Django+Xadmin打造上线标准的在线教育平台—404,403,500页面配置...

    第三百九十一节,Django+Xadmin打造上线标准的在线教育平台-404,403,500页面配置 路由映射 在全局也就是根目录里的urls.py里配置404路由映射 注意:不是写在urlpatte ...

  6. 第二百四十一节,Bootstrap进度条媒体对象和 Well 组件

    第二百四十一节,Bootstrap进度条媒体对象和 Well 组件 学习要点: 1.Well 组件 2.进度条组件 3.媒体对象组件 本节课我们主要学习一下 Bootstrap 的三个组件功能:Wel ...

  7. vue.js项目实战运用篇之抖音视频APP-第十一节: 注册登录及验证码功能

    [温馨提示]:若想了解更多关于本次项目实战内容,可转至vue.js项目实战运用篇之抖音视频APP-项目规划中进一步了解项目规划. [项目地址] 项目采用Git进行管理,最终项目将会发布到GitHub中 ...

  8. 自制深度学习推理框架-第十一节-再探Tensor类并构建计算图的图关系

    自制深度学习推理框架-第十一节-再探Tensor类并准备算子的输入输出 本课程介绍 我写了一个<从零自制深度学习推理框架>的课程,课程语言是 C++,课程主要讲解包括算子实现和框架设计的思 ...

  9. 《从0到1上线微信小游戏》第十一节 接入微信小游戏广告

    第十一节 接入微信小游戏广告 申请公测 开通流量主并创建广告位 广告代码接入实战 广告组件审核 接入广告是小游戏实现盈利的一种方式.笔者会在这一小节讲解如何接入,并列出接入时需要注意的一些问题. 申请 ...

最新文章

  1. 使用python中的Matplotlib绘图示例(续)
  2. C++中#include的工作原理
  3. Python编程语言学习:python中与数字相关的函数(取整等)、案例应用之详细攻略
  4. js弹出对话框的方法总结
  5. Intent.FLAG_ACTIVITY_CLEAR_TOP 的使用注意
  6. 入门Pandas不可不知的技巧
  7. java script 月日年转年月日_javasrcipt日期一些方法和格式转化
  8. 利用shell和iptables实现自动拒绝恶意试探连接SSH服务
  9. 阿里为什么推崇java_为什么阿里巴巴 Java 开发手册推荐使用 LongAdder,而不是 volatile?...
  10. pandas Dataframe删除缺失值
  11. 利用Redis锁解决高并发问题
  12. 第 6 章 MybatisPlus 代码生成器
  13. HTTP 500 - 内部服务器错误的解决
  14. Storm vs. Spark Streaming
  15. linux php服务器搭建,如何搭建linux服务器
  16. WPS公式编辑器快捷键
  17. Mongodb-WeAdmin基于SpringBoot实现的Mongodb管理工具
  18. 区块链 数据交易专利
  19. 123457123457#0#-----com.yuming.TruckCarRun01--前拼后广--大卡车游戏cym
  20. Flutter 闪屏页实现

热门文章

  1. 传统品牌vs新消费品牌社交营销差异化分析报告
  2. oracle中的nls在哪,Oracle的NLS设置
  3. python中下划线开头的命名_Python标识符规则 行与缩进 注释
  4. 作者:​刘新海(1976-),男,博士,中国人民银行征信中心副研究员。
  5. 作者:黄伟(1964-),男,博士,西安交通大学管理学院教授、博士生导师、院长...
  6. 第一届大数据科学与工程国际会议最新、最热会议日程---中国贵阳 2016年5月25-26日...
  7. 作者:聂敏,男,电子科技大学教育大数据研究所博士生。
  8. 【2015年第4期】基于大数据技术的P2P网贷平台风险预警模型
  9. 【云服务】浅析XaaS
  10. 括号匹配不一定用栈哦(洛谷P1739题题解,Java语言描述)