为了防止属性名冲突, JavaScript 介绍了一种 symbols 的类型。在 2015 - 2019 中,symbols 提供一种方法去模拟私有属性。

简介

创建 symbol 最简单的方式是调用 Symbol() 方法。有两个关键属性使得 symbols 变得特殊:

  1. Symbols 可以用于对象 key。只有字符串和 symbol 可以被用于对象 key。
  2. 任何两个 sybmols 都不相等
const symbol1 = Symbol();
const symbol2 = Symbol();symbol1 === symbol2; // falseconst obj = {};
obj[symbol1] = 'Hello';
obj[symbol2] = 'World';obj[symbol1]; // 'Hello'
obj[symbol2]; // 'World'
复制代码

尽管 symbol() 看起来是个对象,实际上它也属于 7 种基本类型。对 Symbol 使用 new 操作符会导致一个错误。

const symbol1 = Symbol();typeof symbol1; // 'symbol'
symbol1 instanceof Object; // false// Throws "TypeError: Symbol is not a constructor"
new Symbol();
复制代码

描述符

Symbol 方法使用单个字符串参数当做描述符。Symbol 的描述符只是用于 debug 的目的。描述符在 symbol 调用 toString 的时候出现。然而,两个相同描述符的 symbol 也是不相等的。

const symbol1 = Symbol('my symbol');
const symbol2 = Symbol('my symbol');symbol1 === symbol2; // false
console.log(symbol1); // 'Symbol(my symbol)'
复制代码

通常情况下,除非你有合适的理由,不然一般不建议使用全局 symbol 注册,这么做有可能导致命名冲突。

命名冲突

JavaScript 中的第一个内置 symbol 是 Symbol.iterator。一个有 Symbol.iterator 方法当做迭代的对象。也就意味着。你可以使用这个对象作为循环的右操作符。

比如获取斐波那契数列:

const fibonacci = {[Symbol.iterator]: function*() {let a = 1;let b = 1;let temp;yield b;while (true) {temp = a;a = a + b;b = temp;yield b;}}
};// Prints every Fibonacci number less than 100
for (const x of fibonacci) {if (x >= 100) {break;}console.log(x);
}
复制代码

为什么 Symbol.iterator 是 symbol 而不是 string? 假设不使用 Symbol.iterator,迭代名定义为一个字符串属性的 iterator。也就是说,假设有一个可迭代的类,如下:

class MyClass {constructor(obj) {Object.assign(this, obj);}iterator() {const keys = Object.keys(this);let i = 0;return (function*() {if (i >= keys.length) {return;}yield keys[i++];})();}
}
复制代码

MyClass 允许你迭代对象 keys。但是上面的类有个潜在的错误。假设用户故意给对象传递一个 iterator 的属性。比如:

const obj = new MyClass({ iterator: 'not a function' });
复制代码

这样的话,迭代就会失效。JavaScript 在你使用 for/of 迭代时,会抛出一个错误 obj is not iterable。这是因为上面的代码覆盖了类中的迭代属性。这是类似原型污染的安全问题。在想当然拷贝用户数据的时候容易发生这样的问题,尤其是 proto 和 constructor 这样的属性。

关键模式在于 symbol 可以清楚的分割用户数据和对象数据。由于符号无法用JSON表示,因此不存在将数据传递到具有错误 Symbol.iterator 属性的 Express API 的风险。 在将用户数据与内置函数和方法(如Mongoose模型)混合的对象中,可以使用符号来确保用户数据不会与内置功能冲突。

私有属性

既然任意两个 symbol 都不相等,symbol 可以方便的模拟 JavaScript 中的私有属性。 Symbols 不会在 Object.key(),中出现,因为除非你明确 export 一个 symbol,没有任何代码可以访问到这个属性,除非使用 Object.getOwnPropertySymbols() 方法。

function getObj() {const symbol = Symbol('test');const obj = {};obj[symbol] = 'test';return obj;
}const obj = getObj();Object.keys(obj); // []// Unless you explicitly have a reference to the symbol, you can't access the
// symbol property.
obj[Symbol('test')]; // undefined// You can still get a reference to the symbol using `getOwnPropertySymbols()`
const [symbol] = Object.getOwnPropertySymbols(obj);
obj[symbol]; // 'test'
复制代码

Symbols 作为私有属性方便的一点是,它不会在 JSON.stringify() 中出现。更详细的内容,请参考这里。

最后

Symbols 处理对象内部状态保证用户数据和程序数据分离是很不错的一个工具。使用 symbols 就不需要再加上各种前缀表示程序状态。下次可以试试 symbol。

JavaScript 中的 Symbols 怎么用相关推荐

  1. 解析JavaScript中的字符串类型与字符编码支持

    JavaScript中的字符串也像Python那样支持反斜杠的转移,并且字符集方面默认为Unicode,下面就来详细解析JavaScript中的字符串类型与字符编码支持 定义 字符串就是零个或多个排在 ...

  2. Javascript中类型的判断

    数据类型的判断有这么几种方式 1.一元运算符 typeOf 2.关系运算符 instanceof 3.constructor 属性 4.prototype属性 一.typeof typeof的返回值有 ...

  3. JavaScript中的数据类型判断

    typeof typeof 操作符返回一个字符串,表示未经计算的操作数的类型. 语法 typeof 运算符后接操作数: typeof operand typeof(operand) 参数 operan ...

  4. 浅析 JavaScript 中的 函数 uncurrying 反柯里化

    柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...

  5. JavaScript中,this的绑定规则

    对于 JavaScript 新手来说,this 是非常基础同时也难以理解的知识点. 比如下面的代码,this 指向就有三种方式. 在<你不知道的 JavaScript>一书中,我总算比较清 ...

  6. Javascript中undefined,NaN等特殊比较

    以下内容转自: http://blog.csdn.net/hongweigg/article/details/38090093 1.问题:在Javascript中,typeof(undefined) ...

  7. Javascript中二进制数据处理方法

    Javascript中二进制数据处理方法 转载于:https://www.cnblogs.com/motadou/archive/2012/02/19/2358514.html

  8. JavaScript 中的有限状态机

    http://www.ibm.com/developerworks/cn/web/wa-finitemach/ JavaScript 中的有限状态机 Page navigation 系列文章 有限状态 ...

  9. 在Javascript中使用面向对象的编程

    by Mike Koss March 26th, 2003 这是一篇,我个人认为最好的,Javascript面向对象编程的文章.翻译不好的地方,还望大家指正,谢谢. 如果您需要,可以访问下面的地址取得 ...

  10. 取出url中的字符_如何在JavaScript中解析URL:例如主机名,路径名,查询,哈希?...

    统一资源定位符(缩写URL)是对Web资源(网页,图像,文件)的引用.URL指定资源位置和检索资源的机制(http,ftp,mailto). 例如,这是此博客文章的URL: 通常,您需要访问URL的特 ...

最新文章

  1. maven项目出现如下错误,求指点;CoreException: Could not calculate build plan:
  2. telnet给服务器发消息,Telnet按字符发送字符串
  3. SAP Analytics Cloud里取出SAP Cloud for Customer的Reports列表
  4. eclipse如何调试(Debug)程序(zhuan)
  5. 配置静态IPV6 NAT-PT
  6. 史上最成功的数学预测:用狄拉克方程推导出电子自旋
  7. Storm入门教程 Storm安装部署步骤
  8. 明年3月开卖!小米11超大杯有望搭载屏下摄像头技术
  9. no such file or directory : 'users/shikx/xxx/xxx/Appirater.m'
  10. # 稳了github star突破9k即时通讯IM开源项目OpenIM版本发布-生产环境重点关注
  11. 用 HBuilder X 编辑 Markdown 文档,如何自定义表格列宽
  12. 想要买房的人究竟有多可悲?! --水木周平
  13. 大脚战场插件怎么关闭_魔兽战场插件 capping插件怎么关闭
  14. 按键精灵移动端系列 - IOS(苹果版)安装1.3.8 deb
  15. Linux(一) VFS虚拟文件系统
  16. 10 本 Linux PDF 书籍免费分享
  17. idea的项目模板的创建
  18. [iOS]上传图片和音视频到阿里云
  19. centos环境下测试网速
  20. 在 ASP.NET Core 中上传文件

热门文章

  1. 车金融|金融产品规则引擎的前世今生(下篇)
  2. 关系图谱服务的技术方案设计
  3. 千锋培训的python
  4. Task9 文件与文件系统
  5. [ROS] KDL + DH 参数 + 正解
  6. 三国志战略版新赛季:先锋斥候北定中原
  7. word中方框中打钩
  8. 捋一捋dubbo配置
  9. 重庆大Vseo这么多年的seo心得
  10. 佛蒙特大学给机器人口述「形态学」,使其「理解」人类指令