本文介绍ES6新增加的数据类型 `Symbol` , 包括基本使用、注意事项以及常用内置 Symbol等。
Symbol 类型介绍

Symbol 是 ES6提供的新特性,表示一种新的原始数据类型,我们可以称之为符号类型,它是 JavaScript 语言中的第七种数据类型,在使用上类似于字符串。JavaScript 语言的数据类型有:null undefined boolean number string object Symbol

console.log(typeof 123);      /* number */
console.log(typeof "abc"); /* string */
console.log(typeof true); /* boolean */
console.log(typeof null); /* object */
console.log(typeof undefined);/* undefined */
console.log(typeof {}); /* object */
console.log(typeof []); /* object */
console.log(typeof Symbol()); /* symbol */

Symbol 类型的意义在于符号类型的数据总是一个独一无二的值,这可以解决对象混入(Mixin)时候因为成员名冲突而导致的覆盖问题。此外,需要注意 Symbol 是基本数据类型值,因此不支持通过 new 以构造函数的方式来调用。

/* Symbol符号类型数据的创建方式 */
/* 1.第一种创建方式 */
let s1 = Symbol();
let s2 = Symbol();
console.log(s1 == s2, s1, s2);
/* 输出:false Symbol() Symbol() */ /* 2.第二种创建方式 */
/* 注解:在创建数据的时候传入一个字符串类似于名字 */
let s3 = Symbol("a");
let s4 = Symbol("b");
let s5 = Symbol("b"); console.log(s3, s4, s5, s3 == s4, s4 == s5);
/* 输出:Symbol(a) Symbol(b) Symbol(b) false false */ /* Symbol解决了什么问题? */
/* 演示代码-01 */
let o1 = {name:"zs",age:18}
let o2 = {name:"lw",address:"BeiJing"};
Object.assign(o1,o2);
console.log(o1);
/* 输出:{ name: 'lw', age: 18, address: 'BeiJing' } */
/* 注解:我们在把 o2 成员混入到 o1 对象中的时候 name键值对因为已经存在所以发生了覆盖。 */ /* 演示代码-02 */
let obj1 = { [Symbol("name")]: "zs", age: 18 }
let obj2 = { [Symbol("name")]: "lw", address: "BeiJing" };
Object.assign(obj1, obj2);
console.log(obj1); /* 输出: */
/*
{ age: 18,
address: 'BeiJing',
[Symbol(name)]: 'zs',
[Symbol(name)]: 'lw'
}
*/

我们知道,在以前对象的键名只能是字符串,当 ES6 引入 Symbol 之后,这也意味着普通对象的 key [属性名] 支持stringSymbol两种类型。不过,需要注意符号类型数据作为对象属性来存储数据的时候有一些小的注意点,下面通过代码来展示这些不同。

/* 符号类型数据作为对象的 key */
/* 方式(1) */
let o1 = { name: "Yong" };
o1[Symbol()] = "Hi@";
console.log(o1) /* { name: 'Yong', [Symbol()]: 'Hi@' } */ /* 注意:无法通过下面这种方式来读取,因为是两个不同的数据 */
console.log(o1[Symbol()]); /* undefined */ /* 方式(2) */
let mySymbol = Symbol();
let o2 = { name: "Yong" };
o2[mySymbol] = "Hello@";
console.log(o2) /* { name: 'Yong', [Symbol()]: 'Hello@' } */ /* 方式(3) */
let symbol_pro = Symbol();
let symbol_fnc = Symbol(); let o3 = {
name: "Yong",
[symbol_pro]: "Nice to meet u",
[symbol_fnc]() {
console.log("调用了函数——symbol_fnc")
}
};
console.log(o3); /*{name: 'Yong', [Symbol()]:'Nice to meet u', [Symbol()]: [Function]}}*/
console.log(o3[symbol_pro]); /* Nice to meet u */
o3[symbol_fnc](); /* 调用了函数——symbol_fnc */ /* 注解:不能直接以点语法的方式来访问符号类型的属性值 */
console.log(o3.symbol_pro); /* undefined */ /* 方式(4) */
let o4 = {name:"Yong"};
let sym = Symbol();
Object.defineProperty(o4, sym, { value: "Xia" });
console.log(o4[sym], o4); /* Xia { name: 'Yong' } */

现在我们知道了 Symbol的特性以及基本使用,其中最重要的一点那就是 Symbol 类型的数据是独一无二的,可是在某些时候我们可能想要对符号类型的数据进行复用,这种情况可以考虑使用Symbol.for方法来创建。 Symbol.for接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol值,如果有那么句直接返回这个已经存在的 Symbol值,如果没有那么就会新建并返回一个以该字符串作为名称的 Symbol值。

/* (1) Symbol.for()  */
/* 1.每次都会创建不同的符号类型数据 */
let s1 = Symbol("foo");
let s2 = Symbol("foo");
console.log(s1, s2, s1 == s2); /* Symbol(foo) Symbol(foo) false */ /* 2.注册以复用(s3 和 s4实际是同一个值) */
let s3 = Symbol.for("test");
let s4 = Symbol.for("test");
console.log(s3, s4, s3 == s4); /* Symbol(test) Symbol(test) true */ /* (2) Symbol.keyFor()
该方法返回一个已经登记的 Symbol类型值的 key,
如果指定的符号类型数据未登记(不是通过 Symbol.for() 来创建,那么将返回 undefined) */ console.log(Symbol.keyFor(s3), Symbol.keyFor(s4)) /* test test */
console.log(Symbol.keyFor(s1), Symbol.keyFor(s2)) /* undefined undefined */
Symbol 类型的数据( 键值对 )并不适用于普通的遍历。
let o = {
id: "41",
name: "Yong",
[Symbol("age")]: 18,
[Symbol("address")]: "QuJin"
} /* 通过for...in 循环遍历 */
for (const k in o) {
console.log(k, o[k])
} /* 打印输出: for...in循环并不能遍历符号类型数据
id 41
name Yong */ console.log(Object.keys(o)); /* [ 'id', 'name' ] */
console.log(Object.getOwnPropertyNames(o)); /* [ 'id', 'name' ] */
console.log(Object.getOwnPropertySymbols(o)); /* [ Symbol(age), Symbol(address) ] */
console.log(Reflect.ownKeys(o));
/* [ 'id', 'name', Symbol(age), Symbol(address) ] */
内置的 Symbol

我们除了可以通过 Symbol() 来创建自定义的符号类型数据外,ES6还为我们提供了内置的 Symbol 值,这些值指向 JavaScript 语言内部使用的方法,下面先简单列出这些内置的 Symbol 值。

Symbol.match              字符串相关方法...
Symbol.replace
Symbol.search
Symbol.split
Symbol.toPrimitive
Symbol.toStringTag
Symbol.unscopables
Symbol.hasInstance 当使用 instanceof 运算符的时候会调用该方法以判断对象是否为构造函数的实例。
Symbol.isConcatSpreadable 布尔类型值,决定 Array.prototype.concat() 是否可以展开。
Symbol.species 当实例化的时候内部会调用该方法,用于提供 this 来创建实例对象。
Symbol.iterator 指向默认的遍历器方法,对象在进行for...of循环的时候会调用该方法。

这里简单通过代码来演示和验证Symbol.hasInstance | Symbol.isConcatSpreadable 的使用。

/* 1.Symbol.hasInstance */
function Person(name, age) {
this.name = name;
this.age = age;
} /* [Function: [Symbol.hasInstance]] */
console.log(Person[Symbol.hasInstance]) let p = new Person("Yong", 18);
console.log(p instanceof Person) /* true */
console.log(Person[Symbol.hasInstance](p)); /* true */
/* 注解:检查 p 对象的原型对象是否在 Person 的原型链上面 */
/* 当执行 p instanceof Person 的时候,内部实际调用的是 Person[Symbol.hasInstance](p) */ /* 2.Symbol.isConcatSpreadable */
let arr1 = [3, 2, 1];
let arr2 = ["abc", "def"];
arr2[Symbol.isConcatSpreadable] = true;
let result = arr1.concat(4, arr2, 456);
console.log(result); /* 当arr2[Symbol.isConcatSpreadable] = true; */
/* result == [ 3, 2, 1, 4, 'abc', 'def', 456 ] */ /* 当arr2[Symbol.isConcatSpreadable] = false; */
/* result == [ 3, 2, 1, 4, ['abc', 'def'], 456 ] */

前端开发系列035-基础篇之Symbol符号类型的更多相关文章

  1. 从0到1用react+antd+redux搭建一个开箱即用的企业级管理后台系列(基础篇)

    背景 ​ 最近因为要做一个新的管理后台项目,新公司大部分是用vue写的,技术栈这块也是想切到react上面来,所以,这次从0到1重新搭建一个react项目架子,需要考虑的东西的很多,包括目录结构.代码 ...

  2. 前端开发:css基础知识之盒模型以及浮动布局。

    前端开发:css基础知识之盒模型以及浮动布局 前言 楼主的蛮多朋友最近都在学习html5,他们都会问到同一个问题 浮动是什么东西?  为什么这个浮动没有效果?  这个问题楼主已经回答了n遍.今天则是把 ...

  3. ESP8266开发之旅 基础篇① 走进ESP8266的世界

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  4. ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  5. ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  6. openlayers5-webpack 入门开发系列一初探篇(附源码下载)

    前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...

  7. leaflet-webpack 入门开发系列一初探篇(附源码下载)

    前言 leaflet-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 w ...

  8. 【Windows10 IoT开发系列】配置篇

    原文:[Windows10 IoT开发系列]配置篇 Windows10 For IoT是Windows 10家族的一个新星,其针对不同平台拥有不同的版本.而其最重要的一个版本是运行在Raspberry ...

  9. ESP8266开发之旅 基础篇④ ESP8266与EEPROM

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  10. ESP8266开发之旅 基础篇⑥ Ticker——ESP8266定时库

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

随机推荐

  1. Python3爬虫批量爬取图片并保存到本地

    看新闻的时候忽然发现了一个图片网站,那肯定得爬一下. 网址:https://www.0xu.cn/ 不难发现,qcmn这个路径对应青春美女 右键检查图片地址可见 访问该地址成功访问到了图片 正式开始 ...

  2. 前端开发者狂喜!30K star开源组件库,界面美观度/开发速度双碾压!

    嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 在前端开发的浩瀚海洋中,寻找一款既能提升开发效率,又能保证界面美观的 UI 组件库,犹如大海 ...

  3. Java 线程的同步与死锁

    目录 1.线程的同步产生的原因 2.线程的同步处理操作 3.线程的死锁情况 排查死锁的方式: 请解释多个线程访问统一资源时需要考虑哪些情况?有可能带来哪些后果? 概念:Java同步和异步,阻塞和非阻塞 ...

  4. 工具 | todesk最新版设备代码、连接密码读取工具,附下载链接

    工具介绍: todesk最新版读取设备代码.连接密码 工具 下载链接: 下载链接: todesk最新版读取设备代码.连接密码 工具下载 使用说明 工具使用效果如图

  5. 106套Axure RP大数据可视化大屏模板及通用组件库

    106套Axure RP大数据可视化大屏模板包括了多种实用美观的可视化组件库及行业模板库,行业模板涵盖:金融.教育.医疗.政府.交通.制造等多个行业提供设计参考. 随着大数据的发展,可视化大屏在各行各 ...

  6. k8s之ingress反向代理pod

    Ingress controller Nginx -->后来改造 Traefik -->也是用于微服务 Envoy  -->微服务 Ingress资源 目前使用0.17.1版本ing ...

  7. 区块链共识算法--PoW

    PoW算法为一种概率算法,其共识结果是临时的,随着时间推移或某种强化,共识结果被推翻的概率越来越小,最终称为事实上结果 1 研究 工作量证明(Proof Of Work,简称POW),简单理解就是一份 ...

  8. SpringSecurity配置 2

    SpringSecurity配置 2 目前的现状,虽然是有了登录认证的接口,但是登录完成后,当我们访问受保护的接口时,即使将 Token 令牌携带与请求一起发送,依然是无法请求成功.另外,提示信息如下 ...

  9. Linux下部署Spring Boot 项目 jar包

    打jar包   在IDEA 2020的最右侧边,选中Maven ,然后双击Lifecycle标签下的package即开始打包,之后就会在target目录下生成jar包. 注意,需要修改pom.xml ...

  10. java LocalDateTime 加减当前时间

      LocalDateTime 可以对当前时间进行加减,在LocalDateTime类中,以plus打头的方法是增加某项时间,如plusDays的请求参数表示将要增加的天数,但是可以为负值:以minu ...