理解ES6中的Symbol
一、为什么ES6引入Symbol
有时候我们在项目开发的过程中可能会遇到这样的问题,我写了一个对象,而另外的同时则在这个对象里面添加了一个属性或是方法,倘若添加的这个属性或是方法是原本的对象中本来就有的,那么这个时候势必会造成冲突,那么为了防止这种冲突,ES6
就引入了Symbol
二、Symbol使用方法
Symbol是一个新的数据类型,所以不要因为Symbol的使用方法的特殊而认为它只是es6中的新的方法。它所代表的是独一无二的,即便其参数一致。
1.使用方法
Symbol的使用方法是Symbol(描述信息),其中描述信息可以为任意类型,但若是引用类型则会调用其toString方法;若为undefined,则为Symbol(),相当于不设置描述信息;若为null则为Symbol(null)。
let name = Symbol("jyy");
let name1 = Symbol("jyy");
console.log(typeof name); // "symbol"
console.log(name); // Symbol(jyy)
console.log(name === name1); // 两个Symbol不相等,false
let obj = {
toString : function(){
return "jyy"
}
};
let obj_name = Symbol(obj);
console.log(obj_name); // Symbol(jyy) 调用引用类型的toString let unf_name = Symbol(undefined);
console.log(unf_name); // Symbol() 相当于没有设置描述信息 let null_name = Symbol(null);
console.log(null_name); // Symbol(null)
从打印出的信息,我们可以看到,其类型是symbol。而且即便在Symbol中的描述字符串设置为相同的内容,最后二者依旧是不相等的。
2.和其他数据类型的关系
我们知道数据类型之间是可以互相转化的,那么Symbol和其他的数据类型之间是如何转化的?
a. 转换为字符串
let name = Symbol("jyy");
console.log(String(name)); // "Symbol(jyy)"
console.log(name.toString()); // "Symbol(jyy)"
console.log("" + name); // 报错TypeError: Cannot convert a Symbol value to a string
可以看出String()和toString()方法是可以转为字符串的,但是不可使用“”+Symbol()转化,回报类型错误
b.转换为布尔值
let name = Symbol("jyy");
console.log(Boolean(name)); // true
if(name){
console.log(true); // 为true
}else{
console.log(false);
}
Symbol类型只要赋值,就一定为true
3.将对象的属性设置为Symbol类型
let name = Symbol("jyy");
let obj = {
name : "beijing",
[name] : "hebei"
};
console.log(obj); // { name: 'beijing', [Symbol(jyy)]: 'hebei' }
console.log(obj.name); // beijing
console.log(obj["name"]); //beijing
console.log(obj[name]); //hebei
若对象的属性为Symbol类型,则Symbol值必须放在[]中,看代码可以体会一下
4.对还有属性为Symbol的对象进行遍历
若属性为Symbol类型,则该属性不会出现在for...in、for...of中,也不会通过使用Object.keys()、Object.getOwnPropertyName()得到,若想要得到,则需要使用Object.getOwnPropertySymbol()
let name = Symbol("jyy");
let obj = {
name : "beijing",
[name] : "hebei"
};
for(let item in obj){
console.log(item); // name 不能遍历Symbol类型属性
}
console.log(Object.keys(obj)); // [ 'name' ] 不能得到Symbol类型属性
console.log(Object.getOwnPropertyNames(obj)); // [ 'name' ] 不能得到Symbol类型属性
console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol(jyy) ] 只得到Symbol类型属性
从上面的代码我们可以看到有些方法可以的得到Symbol类型,有些不行,但是却没有能够完全得到所有类型的。es6中有一个新的方法是可以得到的,如下
let name = Symbol("jyy");
let obj = {
name : "beijing",
[name] : "hebei"
};
console.log(Reflect.ownKeys(obj)); // [ 'name', Symbol(jyy) ]
三、Symbol中的方法
1.Symbol.for()
我们知道Symbo()创建的两个变量永远不会是相同的。那么如果我们需要重新使用同一个Symbol怎么办,总不能需要挨个去进行比较吧。还好,es6为我们提供了Symbol.for()方法。
参数是symbol类型的描述信息,不同于Symbol(),这个而参数只能是字符串或者是undefined,若已经创建了则返回这个symbol,否则就进行创建并将这个新的symbol返回,代码如下
let name = Symbol.for("jyy");
let name1 = Symbol.for("jyy");
console.log(name === name1); // true
请注意,我们在使用创建描述信息为jyy的变量的时候,使用的是for,而不是Symbol(),倘若使用Symbol()进行首次创建,for会再次创建一次,二者不会相等,代码如下:
let name = Symbol("jyy");
let name1 = Symbol.for("jyy");
console.log(name === name1); // false
原因在于Symbol.for()会有一个登记机制,使用for只会对通过for创建的symbol进行检查,不会对Symbol()创建的进行检查。
2. Symbol.keyFor()
这个方法参数是一个通过Symbol.for()创建的symbol类型变量,返回这个symbol变量的描述信息。
let name = Symbol.for("jyy");
console.log(Symbol.keyFor(name)); // "jyy"
let name1 = Symbol("jyy");
console.log(Symbol.keyFor(name1)); // undefined 不能查找Symbol()创建的变量
四、内置的Symbol属性
1.Symbol.hasInstance
这个属性只想一个内部方法,当该对象使用instanceof时,会调用这个方法,代码如下:
let Animal = {
[Symbol.hasInstance](foo){
return true
}
}
let obj = {};
console.log(obj instanceof Animal); // true
另外写下对于原始instaceoOf的原理:
function instanceOf(L,R){
var R_temp = R.prototype; // 获取右侧对象的原型对象
L = L.__proto__; // 获取左侧对象的原型对象
while(true){
if(L == null){// 若左侧对象的原型对象是空,则返回false
return false;
}
if(L === R_temp){ // 若二者的原型对象相等,则说明L是由R直接或间接创建的
return true;
}
L = L.__proto__; // 通过原型链不断向上原型对象
}
}
2.Symbol.isConcatSpreadable
这个属性为一个布尔值,用来表示该对象是否在Array.prototype.concat()时可以展开,干说不懂,代码如下:
let arr = [1,2,3];
let arr1 = [4,5];
console.log(arr1[Symbol.isConcatSpreadable]); // undefined
console.log(arr.concat(arr1)); // [ 1, 2, 3, 4, 5 ], 数组的Symbol.isConcatSpreadable默认为undefined,可以展开(true更可以) arr1[Symbol.isConcatSpreadable] = false;
console.log(arr.concat(arr1)); // [ 1, 2, 3, [ 4, 5, [Symbol(Symbol.isConcatSpreadable)]: false ] ] 设置为false后不可展开
3.Symbol.match
这个属性指向一个方法,当执行str.match(obj)时,会调用这个函数并返回其返回值,代码如下:
class Person{
[Symbol.match](num){
return parseInt(num) > 100; // 自定义方法内的逻辑
}
}
console.log("123".match(new Person())); // true
console.log("12".match(new Person())); // false
4.Symbol.replace
这个属性指向一个方法,当执行str.replace(obj)时,会调用这个方法并返回其返回值,代码如下:
class Person{
[Symbol.replace](obj,rst){ // 两个参数,第一个是对象,第二个是返回的结果
console.log(rst); // wss
return "hello"; // 自定义返回值
}
} console.log("jyy".replace(new Person(), "wss")); // hello
5.Symbol.toPrimitive
这个属性指向一个方法,当对象被转为原始类型时,会调用这个方法,代码如下
let Person = {
[Symbol.toPrimitive](type){ // 参数为三种: string,number,default
switch(type){
case "string":
return "jyy";
case "number":
return 28;
default:
return "Beijing"
}
}
};
console.log("my name: " + String(Person)); //my name: jyy
console.log("my age: " + Number(Person)); // my age: 28
console.log("my address is: " + Person); // my address is: Beijing
6.Symbol.toStringTag
个人感觉这个方法还是比较实用的,最早看到这这个属性的使用是在webpack3打包后的js代码中,用来自定义一个方法的toString()值。我们知道当我们在aler一个对象的时候,会显示[object Object],这个属性指向的方法就是可以将Object换为自定义。代码如下:
let person = {
[Symbol.toStringTag] : "Person"
}
console.log(person.toString()); // [object Person]
理解ES6中的Symbol的更多相关文章
- ES6中的Symbol类型
前面的话 ES5中包含5种原始类型:字符串.数字.布尔值.null和undefined.ES6引入了第6种原始类型——Symbol ES5的对象属性名都是字符串,很容易造成属性名冲突.比如,使用了一个 ...
- 前端知识体系:JavaScript基础-原型和原型链-理解 es6 中class构造以及继承的底层实现原理
理解 es6 中class构造以及继承的底层实现原理 原文链接:https://blog.csdn.net/qq_34149805/article/details/86105123 1.ES6 cla ...
- ES6中的Symbol
---恢复内容开始--- Symbol 1.1 概述 保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突.这就是 ES6 引入Symbol的原因 在es6之前,JavaScript ...
- 理解ES6中的Iterator
一.为什么使用Iterator 我们知道,在ES6中新增了很多的特性,包括Map,Set等新的数据结构,算上数组和对象已经有四种数据集合了,就像数组可以使用forEach,对象可以使用for...in ...
- es6 中的 symbol
symbol 的引入是为了解决对象中的属性名冲突的问题 使用symbol() 函数生成的变量值不与任何的变量值相等, 所有用改变量的值做属性名是不会冲突的 symbol 可以转化为字符串, 可以转化 ...
- 【JS】325- 深度理解ES6中的解构赋值
点击上方"前端自习课"关注,学习起来~ 对象和数组时 Javascript 中最常用的两种数据结构,由于 JSON 数据格式的普及,二者已经成为 Javascript 语言中特别重 ...
- 转载:理解scala中的Symbol
相信很多人和我一样,在刚接触Scala时,会觉得Symbol类型很奇怪,既然Scala中字符串都是不可变的,那么Symbol类型到底有什么作用呢? 简单来说,相比较于String类型,Symbol类型 ...
- 深入理解 ES6中的 Reflect
阅读目录 一:Reflect.get(target, name, receiver) 二:Reflect.set(target,name,value,receiver) 三:Reflect.apply ...
- 理解ES6中的Promise
一.Promise的作用 在ajax请求数据的过程中,我们可以异步拿到我们想要的数据,然后在回调中做相应的数据处理. 这样做看上去并没有什么麻烦,但是如果这个时候,我们还需要做另外一个ajax请求,这 ...
随机推荐
- Python3使运行暂停的方法
在Python3中已经有很大一部分语句与Python2不互通了,运行暂停的方法也有所不同. 1.input(); 这种方法不用包含模块,因此这也是最常用的一种暂停手段. Python2中的raw_in ...
- AI换脸教程:DeepFaceLab使用教程(1.安装及分解视频)
首先需要选择合适的DeepFaceLab下载(https://www.deepfacelabs.com/list-5-1.html),然后安装相应的显卡驱动,如果已经准备好这些工作,那么恭喜你,终于开 ...
- Nginx 502 Bad Gateway 的错误的解决方案
我用的是nginx反向代理Apache,直接用Apache不会有任何问题,加上nginx就会有部分ajax请求502的错误,下面是我收集到的解决方案. 一.fastcgi缓冲区设置过小 出现错误,首先 ...
- python之同步IO和异步IO
linux操作系统基础知识 用户空间和内核空间 操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限.为了保证用户进程不能直接操作内核保证内核的安全,操 ...
- scrapy五大核心组件和中间件以及UA池和代理池
五大核心组件的工作流程 引擎(Scrapy) 用来处理整个系统的数据流处理, 触发事务(框架核心) 调度器(Scheduler) 用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. ...
- HDU-3605-Escape(最大流, 状态压缩)
链接: https://vjudge.net/problem/HDU-3605 题意: 2012 If this is the end of the world how to do? I do not ...
- 【shell】sed指定追加模式空间的次数
最近遇到一个文本复制的场景,需要把文本的每一行都重复输出三次. 这个用awk或者sed实现都还是很简单的. sed代码: [root]$ seq | sed '{h;G;G}' 现在的问题是,如果每行 ...
- shiro框架学习-8-shiro缓存
1. shiro进行认证授权时会查询数据库获取用户角色权限信息,每次登录都会去查询,这样对性能会又影响.可以设置缓存,查询时先去缓存中查找,缓存中没有再去数据库查询. 从shiro的架构图中可以看到有 ...
- k8s实战--redis主从--guestbook
快速入门 实验:通过服务自动发现的redis主从 难点: 1,服务的自动发现,即如何确定coreDNS 已生效 2,redis的主从验证 遇到的问题: 1,Can't handle RDB forma ...
- js 复杂研究
function test_001() { var t =0; return t || out_str("t未定义"), //1 // 执行1句;在执行2句; t||null // ...