symbol

概念

symbol是一个ES6标准种新增的一种基本数据类型,在JavaScript中,共有七种基本数据类型:string、number、bigint、boolean、null、undefined、symbol。并且除了null和undefined之外,每个基本类型都有其包装对象。

symbol 的值是通过 Symbol() 函数生成,每一个 symbol 的值都是唯一的,并且 symbol 类型的值可以作为对象的属性标识符使用,这也是 symbol 类型设计的目的。
所以现在对象属性名可以为两种类型:一种就是原本的字符串类型,一种即为新增的 symbol 类型。凡是使用 symbol 命名的属性都是独一无二的,保证不与其他属性名产生冲突。

JavaScript 中大多数的数值都支持隐式转换为字符串,但 symbol 不会转换:

let s1 = Symbol('sym');
alert(s1); // TypeError: Cannot convert a Symbol value to a string

symbol 也不能与其他类型的值进行运算:

console.log('symbol is' + s1); // TypeError: Cannot convert a Symbol value to a string

但是如果有必要,可以手动将 symbol 转换成字符串

alert(s1.toString());

或者获得定义 symbol 时的描述:

alert(s1.description);

symbol 转换为其他类型:

Boolean(s1); // true
Number(s1); // TypeError: Cannot convert a Symbol value to a number
parseInt(s1); // NaN

用法

创建一个 symbol 的值需要使用 Symbol() 函数,而不能使用 new 命令。

let s1 = Symbol('sym');

由于生成的 symbol 是一个值而不是对象,所以不能为其添加属性。

Symbol() 函数可以接受一个字符串作为参数,表示对该值的描述,因此即使定义 symbol 使用相同的参数互相之间也不是相同的:

let s1 = Symbol('sym');
let s2 = Symbol('sym');
s1 === s2 ; // false

Symbol.for() 、 Symbol.keyFor()

如果我们要重复使用一个 symbol 时,可以用到 Symbol.for() 方法。Symbol.for() 方法接受一个字符串参数,会在全局中搜索有没有以该参数命名的 symbol 的值,如果查找到就返回这个值。如果没有查到则重新生成一个值,并将该值以参数名称注册到全局。

let s1 = Symbol.for('sym'); // 创建
let s2 = Symbol.for('sym'); // 查找
s1 === s2; // true

Symbol.for() 和 Symbol() 方法都会生成新的 symbol 类型的值,不同的是 Symbol.for() 方法会查找命名参数是否在全局中注册过,如果注册过的就不会创建新的值,而是会直接返回,所以我们可以使用到相同的 symbol 值。但使用 Symbol() 方法每次都会创建一个新的值,且不会注册到全局。

Symbol.keyFor() 方法表示获取一个 symbol 的值在全局中注册的命名参数 key,只有使用 Symbol.for() 创建的值才会有注册的命名参数,使用 Symbol() 生成的值则没有:

let s4 = Symbol('sym');
let s5 = Symbol.for('sym');
Symbol.keyFor(s4); // undefined
Symbol.keyFor(s5); // sym

注意使用 Symbol.for() 注册的全局命名参数是真正意义上的全局,而不管是否运行在全局环境。

let iframe = document.createElement('iframe');
iframe.src = 'http://www.baidu.com';
document.body.append(iframe);
iframe.contentWindow.Symbol.for('sym') === Symbol.for('sym'); // true

内置的 symbol 值

除了自定义 symbol 的值,ES6 还提供了 11 个内置的 symbol 值,指向语言内部使用的方法。

Symbol.hasInstance

Symbol.hasInstance 指向一个内部方法,当使用 instanceof 运算符时,判断一个实例是否为某种类型时,会调用这个内部方法。

例如在调用:foo instanceof Foo 时,实际是调用 FooSymbol.hasInstance;

class Foo {[Symbol.hasInstance](foo){return foo instanceof Array;}
}
[1,2,3] instanceof new Foo(); // true

Symbol.isConcatSpreadable

该属性的值是一个布尔型,表示当调用 Array.prototype.concat() 方法时,是否可以展开。
Symbol.isConcatSpreadable的默认值为undefined

例:

let arr = [1,2,3];
arr.concat([4,5]); // [1, 2, 3, 4, 5]

数组默认可以展开,当设置了 Symbol.isConcatSpreadable = false

let arr = [1,2,3];
arr[Symbol.isConcatSpreadable] = false;
arr.concat([4,5]); // [Array(3), 4, 5]

Symbol.species

对象的 Symbol.species 属性指向一个构造函数,在创建衍生对象可以更改构造函数指向。

例:

class MyArr extends Array{}
let a = new MyArr(1,2,3);
let b = a.filter(e => e >= 2);
a instanceof MyArr; // true
b instanceof MyArr; // true

其中变量 b 是变量 a 的衍生对象,变量 b 也是 MyArr 的实例,而通过设置 Symbol.species 可以更改这个衍生对象的构造函数:

class MyArr extends Array{static get [Symbol.species](){return Array;}
}
let a = new MyArr(1,2,3);
let b = a.filter(e => e >= 2);
a instanceof MyArr; // true
b instanceof MyArr; // false

实际上,默认的 Symbol.species 属性等同:

static get [Symbol.species]() {return this;
}

总之该属性实在实例运行过程中,需要再次调用自身构造函数时,可以使用指定的构造函数。

Symbol.match

该属性指向一个函数,当执行 str.match(object) 时,如果该属性存在,会调用该属性指向的方法:

let str = 'e';
class StrObj {[Symbol.match](string){return 'hello'.indexOf(string);}
}
str.match(new StrObj()); // 1
// 等同于
new StrObj()[Symbol.match](str); // 1

Symbol.replace

该属性指向一个方法,当对象被 String.prototype.replace 方法调用时,会执行该方法:

String.prototype.replace(searchValue, replaceValue)
// 等同于
searchValue[Symbol.replace](this, replaceValue)

Symbol.search

对象的 Symbol.search 属性,指向一个方法,当该对象被String.prototype.search 方法调用时,会返回该方法的返回值。

String.prototype.search(regexp)
// 等同于
regexp[Symbol.search](this)

Symbol.split

对象的 Symbol.split 属性,指向一个方法,当该对象被 String.prototype.split 方法调用时,会返回该方法的返回值。

String.prototype.split(separator, limit)
// 等同于
separator[Symbol.split](this, limit)

Symbol.iterator

对象的 Symbol.iterator 属性,指向该对象的默认遍历器方法。

const myIterable = {};
myIterable[Symbol.iterator] = function* () {yield 1;yield 2;yield 3;
};[...myIterable] // [1, 2, 3]

Symbol.toPrimitive

对象的 Symbol.toPrimitive 属性,指向一个方法。该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。

Symbol.toPrimitive 被调用时,会接受一个字符串参数,表示当前运算的模式,一共有三种模式:

  • Number:该场合需要转成数值

  • String:该场合需要转成字符串

  • Default:该场合可以转成数值,也可以转成字符串

      let obj = {[Symbol.toPrimitive](hint) {switch (hint) {case 'number':return 123;case 'string':return 'str';case 'default':return 'default';default:throw new Error();}}};2 * obj // 2463 + obj // '3default'obj == 'default' // trueString(obj) // 'str'
    

Symbol.toStringTag

对象的 Symbol.toStringTag 属性,指向一个方法。在该对象上面调用Object.prototype.toString 方法时,如果这个属性存在,它的返回值会出现在toString方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制 [object Object] 或 [object Array] 中 object 后面的那个字符串。

// 例一
({[Symbol.toStringTag]: 'Foo'}.toString())
// "[object Foo]"// 例二
class Collection {get [Symbol.toStringTag]() {return 'xxx';}
}
let x = new Collection();
Object.prototype.toString.call(x) // "[object xxx]"

Symbol.unscopables

对象的 Symbol.unscopables 属性,指向一个对象。该对象指定了使用with关键字时,哪些属性会被 with 环境排除。
即使用 Symbol.unscopables 指定的对象,在使用 with 语法块时,不在当前作用域中寻找特定属性,而是从外层作用域开始查找。

// 没有 unscopables 时
class MyClass {foo() { return 1; }
}var foo = function () { return 2; };with (MyClass.prototype) {foo(); // 1
}// 有 unscopables 时
class MyClass {foo() { return 1; }get [Symbol.unscopables]() {return { foo: true };}
}var foo = function () { return 2; };with (MyClass.prototype) {foo(); // 2
}

应用场景

  • 使用 symbol 作为对象的属性名
    由于每一个 symbol 的值都是不相同的,所以使用 symbol 作为属性名可以保证不会出现同名属性。防止某一个属性被改写覆盖:

    let s1 = Symbol(‘sym’);
    let obj = {
    name: ‘test obj’,
    [s1]: ‘this is symbol’
    }
    obj[s1]; // this is symbol

注意使用 symbol 作为对象的属性名时,是无法通过 Object.keys() 和 for…in 来遍历对象的属性的:

Object.keys(obj); // ["name"]for(let name in obj){console.log(name); // name
}

因此,在将对象进行 JSON 转换时: JSON.stringify() ,symbol 的属性也会被排除:

JSON.stringify(obj); // "{"name":"test obj"}"

需要注意的是,使用 symbol 定义的属性,还是公有的属性,不是私有属性。

  • 使用 symbol 定义常量
    使用 symbol 定义的常量能保证常量的值都是不相等的。

      const COLOR_RED    = Symbol();const COLOR_GREEN  = Symbol();function getComplement(color) {switch (color) {case COLOR_RED:return COLOR_GREEN;case COLOR_GREEN:return COLOR_RED;default:throw new Error('Undefined color');}}
    

Refer: https://es6.ruanyifeng.com/#docs/symbol

理解JavaScript基本数据类型symbol相关推荐

  1. 理解javaScript的数据类型之字符串类型

    js中有六大数据类型,在es6中又新增了symbol唯一数据类型,这七大数据类型支撑起了整个javaScript的生态环境. 六大数据类型其中又分为: 基本数据类型:String字符串.Number数 ...

  2. js 对象深拷贝_这一次,彻底理解JavaScript深拷贝

    导语 这一次,通过本文彻底理解JavaScript深拷贝! 阅读本文前可以先思考三个问题: JS世界里,数据是如何存储的? 深拷贝和浅拷贝的区别是什么? 如何写出一个真正合格的深拷贝? 本文会一步步解 ...

  3. 西门子for循环例子_理解JavaScript中的循环缺陷和迭代协议

    如果您已经用JavaScript或任何语言编程了一段时间,for-循环对你来说不应该陌生.您没有注意到许多编程语言,包括JavaScript,已经从使用for-循环使用迭代器-返回给定集合的下一项的对 ...

  4. html js定义一个变量的值,JavaScript的数据类型与变量的解析(附示例)

    本篇文章给大家带来的内容是关于JavaScript的数据类型与变量的解析(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 这篇文章,来聊聊 JS 中的数据类型与变量.这是在学 ...

  5. 深入理解javascript函数系列第二篇——函数参数

    前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数.本文是深入理解javascript函数 ...

  6. 前端之 JavaScript 常用数据类型和操作

    JavaScript 常用数据类型有:数字.字符串.布尔.Null.Undefined.对象 JavaScript 拥有动态类型 JavaScript 拥有动态类型.这意味着相同的变量可用作不同的类型 ...

  7. php解析js的 arraybuffer_JS的所谓的第七种数据类型Symbol

    首先,为什么说叫所谓呢?因为在2007年之前Js给予我们typeof解析数据类型的一共有六种(一直有争议,但是我们暂时就按typeof来算) 'function''Number''Object''bo ...

  8. 浏览器解析jsx_简单理解JavaScript,TypeScript和JSX

    原标题:简单理解JavaScript,TypeScript和JSX Java: 基本概念: Java一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为Java引 ...

  9. 深度解析javaScript常见数据类型检查校验

    前言 在JavaScript中,数据类型分为两大类,一种是基础数据类型,另一种则是复杂数据类型,又叫引用数据类型 基础数据类型:数字Number 字符串String 布尔Boolean Null Un ...

最新文章

  1. 分布式为什么一定要有高可用的分布式锁?一线大厂必看!
  2. linux shell 判断字符串是否在数组中
  3. Entity Framework 代码模板
  4. PHP中集成PayPal标准支付
  5. 函数创建对象(2)原型模式
  6. 按字母位置关系给数字排序(洛谷P4414题题解,Java语言描述)
  7. poi为什么所有celltype都是string_不是所有向日葵都向阳,你知道为什么吗
  8. 为什么今年好多人开始买基金了,是疫情影响的吗?
  9. 注册表添加 右键功能
  10. C语言之内存分配函数
  11. 计算机专业 美国,美国计算机专业的五大名校概况
  12. 软件基本功:以视频通话为例,交叉测试表格
  13. OLTP-Bench Testbed
  14. java验证码不显示_chrome无法显示Java生成的验证码图片
  15. excel随机数_【收藏】Excel生成随机数、不重复随机数技巧,试验检测办公必备...
  16. c语言中布尔类型字节数,【C语言】中的布尔类型
  17. SecTalks: BNE0x00 - Minotaur靶机
  18. idea选中多行的一列、一竖(不是多行的全部内容)
  19. pip安装报错: unable to creat process using ‘“‘的解决方法
  20. 超详细python下简单快速下载opencv

热门文章

  1. ParameterizedType类的使用
  2. [Git] 本地代码库和远程同步
  3. 蒙古风币wsec引起社会广泛讨论关注
  4. java中collector使用_怎么在java中创建一个自定义的collector
  5. Java语言进阶:网络编程入门
  6. USACO Broken Necklace模拟
  7. 你知道你的电脑1秒钟能做多少事情吗?(转)
  8. 2021年终总结暨2022新年计划
  9. SIP中的早期媒体early media与回铃音
  10. 宝藏级UI组件库:FirstUI,微信小程序版+uniapp版双版至V1.5.0,完美支持vue3