理解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请求,这 ...
随机推荐
- 我来说说XML文件中的xmlns、xmlns:xsi和xsi:schemaLocation、dtd文件的具体含义
文章摘自:https://yq.aliyun.com/articles/40353 http://www.cnblogs.com/zhao1949/p/5652167.ht ...
- python grobal 的使用方法
写一个功能,运行报错,name 'number' is used prior to global declaration ,查资料梳理一下 因为这个函数需要调用多次,第一次调用的时候,走if语句,后面 ...
- CentOS7安装并使用Ceph
1.准备工作1.1 安装配置NTP官方建议在所有 Ceph 节点上安装 NTP 服务(特别是 Ceph Monitor 节点),以免因时钟漂移导致故障. ln -sf /usr/share/zonei ...
- JS 循环遍历 总结
一.循环遍历语句 for...in... (ES5) 语法:javascript for(keys in obj){} 适用:遍历对象 说明: 1.keys表示obj对象的每一个键值对的键(键名),所 ...
- 编译安装cmake
安装cmake 1.为什么用cmake? mysql部分版本安装前编译需要用软件cmake,而不是我们之前通常使用的make! 百度百科:CMake 可以编译源代码.制作程式库.产生适配器(wr ...
- 一个web应用的诞生(7)
现在所有的Py代码均写在default.py文件中,很明显这种方法下,一旦程序变的负责,那么无论对于开发和维护来说,都会带来很多问题. Flask框架并不强制要求项目使用特定的组织结构,所以这里使用的 ...
- 软件安装:树上分组DP/tarjan缩点/(也许基环树?)
提炼:tarjan环缩成点,建0虚根,跑树形DP,最难的是看出可能有n个点n条边然后缩点,n个点n条边可能不只有一个环 n个点n条边->基环树: 基环树,也是环套树,简单地讲就是树上在加一条边. ...
- ZROI 19.08.02 杂题选讲
给出\(n\)个数,用最少的\(2^k\)或\(-2^{k}\),使得能拼出所有数,输出方案.\(n,|a_i|\leq 10^5\). 显然一个绝对值最多选一次.这个性质非常强. 如果所有都是偶数, ...
- thinkphp之session操作
原理机制 配置部分 代码部分 助手函数 借助第三方介质存入session 从负载均衡角度考虑----最好放在memocache,redis
- cursor-spacing 软键盘和input的距离
指定光标与键盘的距离,单位 px .取 input 距离底部的距离和 cursor-spacing 指定的距离的最小值作为光标与键盘的距离. 例: 软键盘和input的距离300px