目录

Symbol类型

介绍

Symbol.prototype.description

Symbol的应用

1 给对象内追加属性

2 消除魔术字符串

symbol属性名的遍历

Symbol.for()&&Symbol.keyFor()

Symbol.for(key)

Symbol.keyFor(sym)


Symbol类型

介绍

ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol的原因。

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值,是一种类似于字符串的数据类型,它是 JavaScript 语言的第七种数据类型,前六种是:undefinednull、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)

Symbol 值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

symbol的特点:

  1. 提供独一无二的值

  2. Symbol 值作为对象属性名时,不能用点运算符,要用中括号表示法

  3. Symbol 值作为对象属性名时,该属性不会出现在for...infor...of循环中

Symbol函数可以接受参数,表示对于这个唯一值的描述。即使参数一致,symbol值也不一样。

// 没有描述符的symbol值
let s = Symbol();
// 有描述符的symbol值
let s1 = Symbol('hello');
console.log(s, s1);  //Symbol() Symbol(hello)
console.log(typeof s);  //symbol

 symbol值是一个独一无二的值。

// 没有参数的情况
let s1 = Symbol();
let s2 = Symbol();s1 === s2 // false// 有参数的情况
let s1 = Symbol('foo');
let s2 = Symbol('foo');s1 === s2 // false

Symbol.prototype.description

获取 Symbol 的描述。创建 Symbol 的时候,可以添加一个描述,ES2019 提供了一个实例属性description,直接返回 Symbol 的描述。如果没有描述则返回undefined。

const sym = Symbol('foo');
sym.description // "foo"

Symbol的应用

1 给对象内追加属性

由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。

假设有一个obj内部的属性都是不可枚举属性,不动其他属性的情况下,现需要在obj内放一个值'张三',属性名无所谓。你知道obj对象内有什么属性吗?肯定不知道对不对,好,那现在往对象里添加一个属性,值为'张三',你敢添加吗?假设你要添加的属性名是name,那么会出现两种情况,要么obj内没有name属性,你添加成功,要么obj内有name属性,你覆盖了人家原来的值。这时候symbol的作用就出来了。

let obj = {// ...此处省略n多个属性name: 'ronda'
};
// 因为symbol是独一无二的,那么属性名就可以用symbol来表示。
let tempName = Symbol('name');
obj[tempName] = '张三';  // '张三'保存到了obj对象中
console.log(obj[tempName]);  //张三
console.log(obj);

2 消除魔术字符串

魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良好的代码,应该尽量消除魔术字符串,改由含义清晰的变量代替。

案例一:

function getArea(shape, options) {let area = 0;switch (shape) {case 'Triangle': // 魔术字符串area = .5 * options.width * options.height;break;/* ... more code ... */}return area;
}getArea('Triangle', { width: 100, height: 100 }); // 魔术字符串

上面代码中,字符串Triangle就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护。

代码耦合:一个软件结构内不同模块之间互连程度的度量(耦合性也叫块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差,模块间耦合的高低取决于模块间接口的复杂性,调用的方式以及传递的信息。

常用的消除魔术字符串的方法,就是把它写成一个变量。

const shapeType = {triangle: 'Triangle'
};function getArea(shape, options) {let area = 0;switch (shape) {case shapeType.triangle:area = .5 * options.width * options.height;break;}return area;
}getArea(shapeType.triangle, { width: 100, height: 100 });

上面代码中,我们把Triangle写成shapeType对象的triangle属性,这样就消除了强耦合。

如果仔细分析,可以发现shapeType.triangle等于哪个值并不重要,只要确保不会跟其他shapeType属性的值冲突即可。因此,这里就很适合改用 Symbol 值。

const shapeType = {triangle: Symbol()
};
// 通过shapeType.triangle 使用

上面代码中,除了将shapeType.triangle的值设为一个 Symbol,其他地方都不用修改。

案例二:

let obj = {attr1: Symbol('one'),attr2: Symbol('two'),attr3: Symbol('three'),attr4: Symbol('four'),
};
function test(param) {switch (param) {case obj.attr1:console.log('这是one的操作');break;case obj.attr2:console.log('这是two的操作');break;case obj.attr3:console.log('这是three的操作');break;case obj.attr4:console.log('这是four的操作');break;default:console.log('这是默认的操作');break;}
}
test(obj.attr1);  //这是one的操作

symbol属性名的遍历

Symbol 作为属性名,遍历对象的时候,该属性不会出现在for...infor...of循环中,也不会被Object.keys()Object.getOwnPropertyNames()JSON.stringify()返回。

但是,它也不是私有属性,有一个Object.getOwnPropertySymbols()方法,可以获取指定对象的所有 Symbol 属性名。该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

const obj = {};
let a = Symbol('a');
let b = Symbol('b');obj[a] = 'Hello';
obj[b] = 'World';const objectSymbols = Object.getOwnPropertySymbols(obj);objectSymbols
// [Symbol(a), Symbol(b)]

下面是另一个例子,Object.getOwnPropertySymbols()方法与for...in循环、Object.getOwnPropertyNames方法进行对比的例子。

const obj = {};
const foo = Symbol('foo');obj[foo] = 'bar';for (let i in obj) {console.log(i); // 无输出
}Object.getOwnPropertyNames(obj) // []
Object.getOwnPropertySymbols(obj) // [Symbol(foo)]

另一个新的 API,Reflect.ownKeys()方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。

let obj = {[Symbol('my_key')]: 1,enum: 2,nonEnum: 3
};Reflect.ownKeys(obj)
//  ["enum", "nonEnum", Symbol(my_key)]

由于以 Symbol 值作为键名,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。

Symbol.for()&&Symbol.keyFor()

有时,我们希望重新使用同一个 Symbol 值,Symbol.for()方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。

全局 symbol 注册表中的一个记录结构如下:

字段名 字段值
[[key]] 一个字符串,用来标识每个 symbol
[[symbol]] 存储的 symbol 值

Symbol.for(key)

Symbol.for(key) 方法会根据给定的键 key,来从运行时的 symbol 注册表中找到对应的 symbol,如果找到了,则返回它,否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中。

语法: Symbol.for(key); 参数: key 一个字符串,作为 symbol 注册表中与某 symbol 关联的键(同时也会作为该 symbol 的描述)。 返回值: 返回由给定的 key 找到的 symbol,否则就是返回新创建的 symbol。

Symbol.for("foo"); // 创建一个 symbol 并放入 symbol 注册表中,键为 "foo"
Symbol.for("foo"); // 从 symbol 注册表中读取键为"foo"的 symbol
Symbol.for("bar") === Symbol.for("bar"); // true,证明了上面说的
Symbol("bar") === Symbol("bar"); // false,Symbol() 函数每次都会返回新的一个 symbollet sym = Symbol.for("mario");
sym.toString();
// "Symbol(mario)",mario 既是该 symbol 在 symbol 注册表中的键名,又是该 symbol 自身的描述字符串,为了防止冲突,最好给你要放入 symbol 注册表中的 symbol 带上键前缀。
Symbol.for("mdn.foo");
Symbol.for("mdn.bar");

Symbol.keyFor(sym)

Symbol.keyFor(sym) 方法用来获取全局symbol 注册表中与某个 symbol 关联的键。 该方法返回一个已登记的 Symbol 类型值的key。 语法: Symbol.keyFor(sym); 参数: sym 必选参数,需要查找键值的某个 Symbol 。 返回值: 如果全局注册表中查找到该symbol,则返回该symbol的key值,返回值为字符串类型。否则返回undefined

// 创建一个全局 Symbol
let globalSym = Symbol.for("foo");
Symbol.keyFor(globalSym); // "foo"let localSym = Symbol();
Symbol.keyFor(localSym); // undefined// 以下Symbol不是保存在全局Symbol注册表中
Symbol.keyFor(Symbol.iterator) // undefined

ES6 Symbol类型的应用、symbol属性名的遍历、Symbol.for()Symbol.keyFor()相关推荐

  1. java遍历一个类的属性名,java遍历对象属性

    java对象动态添加属性,Class对象和Java反射机制,java遍历对象属性,js对象动态添加属性 java 对象动态添加属性,Class对象和Java反射机制,java遍历对象属性,js对象动态 ...

  2. Symbol()类型的定义及特点

    前文我们提到了JavaScript中的两种数据类型的存储方式,在说到数据类型的时候,提到了ES6新增的一种数据类型:Symbol类型,这个类型的功能类似于一种标识唯一性的ID.Symbol类型属于Ja ...

  3. es6 遍历 Symbol 属性名

    遍历 Symbol 属性名 Symbol 作为属性名,该属性不会出现在for...in.for...of循环中,也不会被Object.keys().Object.getOwnPropertyNames ...

  4. es6 作为属性名的 Symbol

    作为属性名的 Symbol 由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性.这对于一个对象由多个模块构成的情况非常有用 ...

  5. ES6新特性_ES6对象添加Symbol类型属性---JavaScript_ECMAScript_ES6-ES11新特性工作笔记016

    然后我们再来看,给对象添加symbol类型的属性, 这个这样做的目的就是: 保证我们添加的方法或属性是唯一的,因为我们知道 我们的symbol这个属性是有唯一性的. 首先我们有个 let game = ...

  6. ES6笔记(4)-- Symbol类型

    系列文章 -- ES6笔记系列 Symbol是什么?中文意思是标志.记号,顾名思义,它可以用了做记号. 是的,它是一种标记的方法,被ES6引入作为一种新的数据类型,表示独一无二的值. 由此,JS的数据 ...

  7. JavaScript 为什么要有 Symbol 类型?

    摘要: 为什么比怎么用更有意义. 原文:JavaScript 为什么要有 Symbol 类型 作者:前端小智 Symbols 是 ES6 引入了一个新的数据类型 ,它为 JS 带来了一些好处,尤其是对 ...

  8. 简述 Symbol 类型用途

    应用场景1:使用Symbol来作为对象属性名(key) Symbol类型的key是不能通过Object.keys()或者for-in来枚举的,它未被包含在对象自身的属性名集合(property nam ...

  9. 如何实现一个深拷贝(考虑循环引用对象、和symbol类型)

    文章目录 第一步:简单实现 第二步:拷贝数组 第三步:循环引用 1.使用哈希表 2.使用数组 第四步:拷贝 Symbol 第一步:简单实现 其实深拷贝可以拆分成 2 步,浅拷贝 + 递归,浅拷贝时判断 ...

最新文章

  1. 用python给自己写一个加密算法
  2. Php数组面包屑导航,PHP 导航提示(面包屑型轨迹)
  3. PAT甲级1131 Subway Map (30分):[C++题解]堆优化dijkstra、单源最短路、地铁地图、巧妙地建图套dijkstra模板!!
  4. Py之re:re正则表达式库的简介、常用函数、经典案例之详细攻略
  5. for 创建一个方法:键盘录入一个数 ,求它的 阶乘 及 阶乘的和
  6. DIV中文字不换行解决办法
  7. c++判断奇偶_高中数学奇偶性说课稿范文
  8. 【华为云技术分享】开发团队中的任务没人领取,你头疼吗?
  9. 做好产品的孵化器 淘特上线10元店、淘特100
  10. linux之chroot命令
  11. Android设备的ID
  12. 软件工程--可行性研究
  13. 联想ghost重装系统_史上最全的重装ghost系统错误解决方法大全
  14. Apache FTPServer本地部署FTP服务
  15. nginx配置错误导致的目录穿越漏洞
  16. 金融学经济学字母含义
  17. 百度云生态分享日 | AI技术实践与应用沙龙活动成功举办
  18. 如何在手机上收发邮件?
  19. 2023团体程序设计天梯赛--正式赛
  20. centos7搭建DNS服务,CA字签证书

热门文章

  1. 论文阅读 (86):Normality Guided Multiple Instance Learning for Weakly Supervised Video Anomaly Detection
  2. 用户名只能含有英文字母php,新增用户提示“『用户名』只能是字母和数字的组合三位以上。”...
  3. 检查安装的 DirectX 版本
  4. 新能源汽车设备线材的绝缘总线测试,如何用线束测试仪测?
  5. jquery实现QQ新闻图片滚动
  6. java 2048游戏_JAVA2048游戏 本课程设计是基于java语言的2048小游戏设计 联合开发网 - pudn.com...
  7. vray4.0渲染AO、线稿及阴影
  8. 2202: 合并链表(线性表)
  9. 嘀嗒出行4年未获新融资,市场、法规双压下亟待上市自救
  10. 『往事』之---我的童年少年时代(续)