一念之差,错失良机!浅谈基础类型之Symbol,给你的笔试多加一分~

前言

12月初的时候,我打算将阮大大的《ECMAScript6 入门》作一个笔记,顺带做为参考的,可是这个文章已经在11号左右的时候流产了。为何呢?一个是由于最近主管给分配了任务,没啥时间作;还有一个缘由就是:尼玛看不懂了啊!!!javascript

最近事情少了,回过头继续学习,看到一个有意思的玩意:Symboljava

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。es6

原始数据类型??这让我想起来以前的一道笔试题:JavaScript数据类型有哪些?面试

当时我写的是:undefined、null、number、string、boolean、Object。面试官问了我一句,数据类型就是这些了吗?我内心有个Symbol的印象,可是当面试官继续问做用的时候我哑然了,由于个人确没了解过具体这东西是干吗的呀?因而面试官给我讲起了Symbol的相关知识:数组

概述

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

基本用法

let s = Symbol();

typeof s // => "symbol" 
复制代码

这好像和之前生成对象的写法不太同样,没有用new命令,你问我为何?废话用new命令那不就是对象了吗?Symbol是原始数据类型呀!和对象是并列关系~学习

有的童鞋会问,用Symbol()生成的话,很不利于阅读呀,谁知道这个Symbol是干吗的呢?不要紧,Symbol已经帮咱们想好了解决办法:ui

Symbol函数能够接受一个字符串做为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。this

let s1 = Symbol('s1'); // => Symbol(s1)
let s2 = Symbol('s2'); // => Symbol(s2)
let s3 = Symbol('s1'); // => Symbol(s1)
复制代码

这时候又有好奇宝宝要问了,加上了描述,这两个Symbol值是否是就变成同样的了?spa

s1 == s3 // => false
s1 === s3 // => false
复制代码

不论是==仍是===,返回值都是false,这说明:

Symbol函数的参数只是表示对当前 Symbol 值的描述,所以相同参数的Symbol函数的返回值是不相等的。

类型转换

Symbol 值不能与其余类型的值进行运算,会报错。

let s = Symbol('s');
s + ' is a Symbol!' // => index.js:13 Uncaught TypeError: Cannot convert a Symbol value to a string
复制代码

Symbol 值能够显式转为字符串。

let s = Symbol('s');
s.toString(); // => Symbol(s)
s.toString() + ' is a Symbol!' // => Symbol(s) is a Symbol!
复制代码

能够看到这时候能够和字符串相加了。

Symbol 值也能够转为布尔值,可是不能转为数值。

let s = Symbol();
Boolean(s); // => true
!s // => false

Number(s); // => TypeError: Cannot convert a Symbol value to a number
Number(s) + 2; // => TypeError: Cannot convert a Symbol value to a number
复制代码
  • 上面给Symbol添加的描述,要想获取的话只能经过toString()显式转换,比较不方便

ES2019 提供了一个实例属性description,直接返回 Symbol 的描述。

let s = Symbol('this is a Symbol');
s.description // => this is a Symbol
复制代码

Symbol用法

Symbol 值能够做为标识符,用于对象的属性名。

有人问了,我用字符串作属性名,又快又方便,为何要用Symbol呢?

这个问题问的好,不少学习不细心(可能只有我一个)的童鞋就有这样的疑问!

咱们来看看上面对Symbol的介绍:

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。

是的,独一无二,你有没有在开发中遇到变量名相似的状况,苦于不知道怎么区分?你是否在操做其余同事编写的对象的时候,惧怕本身添加的变量名将其余变量覆盖,或者被其余变量覆盖呢?这时候你就须要一个Symbol值来续命(+ 1s)了!

做为属性名使用

let s = Symbol();
// 第一种写法
let obj = {
    [s]: 'hello Symbol'
}

// 第二种写法
let obj = {};
obj[s] = 'hello Symbol'

// 第三种写法
let obj = {};
Object.defineProperty(obj,s,{value:'hello Symbol'})

// 以上三种写法的结果都是
obj[s]; // => hello Symbol
复制代码

注意

  • Symbol值做为属性名,读取时不能使用点运算符
  • 在对象内部使用Symbol值做为属性名时,必须放在方括号中

做为属性名时的遍历

Symbol 做为属性名,遍历对象的时候,该属性不会出如今for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。

for大法都没法遍历?那是否是私有属性?回答是:NO,对象提供了一个Object.getOwnPropertySymbols()方法用于获取对象内全部Symbol属性名,返回一个数组

实例:消除魔术字符串

消除魔术字符串

Symbol.for()

有时,咱们但愿从新使用同一个 Symbol 值,Symbol.for()方法能够作到这一点。

let s1 = Symbol.for('s');
let s2 = Symbol.for('s');
s1 === s2; // => true
复制代码

那么问题来了:SymbolSymbol.for的区别是什么呢?

前者会被登记在全局环境中供搜索,后者不会。Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,若是不存在才会新建一个值。

面试结束

到这个时候面试已经结束

但我感受事情可能并无想象中的那么简单

内置的Symbol值

回看一下阮大大的教程最后:

除了定义本身使用的 Symbol 值之外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。

Symbol.hasInstance

对象的Symbol.hasInstance属性,指向一个内部方法。当其余对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法。

function fn(){
    
}
let ins = new fn();
ins instanceof fn; // => true
fn[Symbol.hasInstance](ins); // => true
复制代码

Symbol.isConcatSpreadable

对象的Symbol.isConcatSpreadable属性等于一个布尔值,表示该对象用于Array.prototype.concat()时,是否能够展开。

let arr1 = ['a','b'];
let arr2 = ['c','d'];
arr1.concat(arr2); // => ['a','b','c','d']

arr2[Symbol.isConcatSpreadable] = false;
arr1.concat(arr2); // => ['a','b',['c','d']]
复制代码

Symbol.species、Symbol.match、Symbol.relpace、Symbol.search、Symbol.split.....

这些咱也不知道有啥用,咱也看不懂,等后面有闲工夫再去研究吧~

相关文章
相关标签/搜索