本文将从浅层,让初学者理解如何使用
Symbol、
Symbol.hasInstance.
先聊聊什么是Symbol
Symbol是基本数据类型,和字符串,数组,没啥区别。
创建一个Symbol的方式是。
let Symbol = Symbol()
let aSymbol = Symbol()
let astring = String()
console.log(typeof aSymbol);//输出结果 Symbol
console.log(typeof astring);//输出结果 String
Symbol类型作为一种基本数据类型和字符串类型有着相似的特性。
Symol无法通过字面量进行创建
我们都知道字符串可以直接
let str = 'hi'
而Symbol却不行,Symbol创建的方式只有Symbol()
为什么会这样呢? 因为Symbol的特点就是,独一无二。
你无法写出一个独一无二的值。
Symbol设计的初衷是为了解决命名冲突问题,因为在一个对象里面,当你使用其他人创建的对象,而这个对象里面方法很多,而你想在这个对象里面添加方法的时候,有时很难做到命名不冲突。
所以当你想在对象里面创建一个绝对不会冲突的命法名或者属性名时,Symbol 就可以做到这一点。
你可以先把Symbol() 这个函数,想象成随机生成一个字符串,但这个字符串的生成,不会与代码块中的任何一个字符串重复。
比如
let test1 = Symbol()
let test2 = Symbol()
你可以理解为
test1 = ‘Xasduiadh1’
test2 = ‘siuwii12u89da’
你不需要知道内部实现原理是什么,你只需要知道,Symbol()就是可以实现永远生成不同的字符串。
当然这只是便于你的一种理解方式,内部实现,我猜应该不是这样。。
同时,在创建Symbol的时候我们还可以加上描述字符串
const sym1 = Symbol('foo');
const sym2 = Symbol('foo');
console,log(sym1===sym2)//false
这个描述字符串,只起描述作用,不会影响Symbol()函数创建的独一无二的特点。
也就是说,你依然可以理解为
sym1=‘sadnai13addsdasxzc’
sym2 = ‘ioinjaaiosjdoajda’
而里面的参数只不过是来描述这个字符串的,他们起了相同的描述名,而却不是同一内容。
就像你我都可以把
鲤鱼和鲨鱼都描述成鱼
而鲤鱼和鲨鱼完全是不一样的。
Symbol的使用场景。
举个例子
我们的目的是给game对象添加俩属性。
现在我告诉你,假设game对象里面有一亿个方法。
请问如何做到命名不重复?
就用如下代码实现
let game = {···
}//这里game对象里面有很多属性和方法所以我把它折叠了。
let methods = {
up: Symbol(),
down: Symbol()
}
game[methods.up] = function () {
console.log('upupup');
}
game[methods.down] = function () {
console.log('downdowndown');
}
这里game对象和method对象都是普通的对象
我们在method对象里写了两个属性
up 和 down,然后紧接着让up与down成为了独一无二的值, 因为Symbol()这个函数就是实例化一个独一无二的值。(你依然可以坚持把它理解为字符串,不过更推荐理解成一个抽象的概念,就是独一无二的值。因为毕竟Symbol类似字符串,但不是字符串)。
接下来,我们在game对象里 创建两个方法。
回忆一下
对象创建的方法有两种 obj.xx和obj[‘xx’]
obj在这里表示一个普通对象。
如果用obj[‘xx’]在 []里面必须是个字符串,由于Syboml()就是类似字符串的一种数据类型,so。
game[methods.up] 便拿到了那个独一无二的Symbol值。
为了方便理解,我们这样想。
假设method.up对应的一个独一无二的Symbol()的值为’XXX1231XDAD’是一个字符串。
那么现在我们用game[method.up] = function(){}
其实相当于
game[‘XXX1231XDAD’] = funtion(){}
其实本质上也是给它添加了一个方法。
不过这个方法,独一无二,不会与任何方法重复,因为没有方法的名字会是[‘XXX1231XDAD’]。(哈哈) , 所以Symbol()的值就是独一无二的。
所以我们game[method.up]() 就会输出’upupup’
这便是使用独一无二的Symbol()去给一个有很多方法的对象添加方法的方式,这种方法,绝不重复。
补充
对于一个已经声明好了的symbol值的一个变量
let sym = Symbol('这是描述字符串')
我们可以用.description来获取它的描述
console.log(sym.description)//‘这是描述字符串’
Symbol.hasInstance
要理解Symbol.hasInstance首先要知道,这是一个内置Symbol值。
这意味着它已经声明好了,是一个已经声明好了的Symbol值,需要的时候,直接使用就行了,使用方式和Symbol具有相似之处,作为方法名或者属性名的时候都是要以[]的形式。
我们来看看作为一个原始的对象里面是如何创建属性与方法的。
由于语法的演变。
创建属性和创建方法一共有如下几种方式。
1.创建属性
(1)当obj直接是个对象的时候在外面创建
let obj = {}
obj.att1 = 1;
obj['att2']=2;
console.log(obj)//{ att1: 1, att2: 2 }
(2)声明的时候创建,以键值对的方式
let obj = {
att1: 1,
['att2']: 2,
}
console.log(obj)//{ att1: 1, att2: 2 }
2.创建方法,创建方法其实和创建属性很像
创建属性: 是让对象里的变量(我们姑且叫一种十分特殊的变量)指向数字或者字符串。
创建方法: 是让对象里的变量(我们姑且叫一种十分特殊的变量) 指向一个函数。
对象里面创建方法的方式
1.
let obj = {
method1: function () {
console.log('我是方法1');
},
['method2']: function () {
console.log('我是方法2');
}
}
其实和创建属性的方式很像,不过在:后面我们这次写的是个函数。
我们也可以把他们声明方式写在一起便于比较
let obj = {
att1: 1,
['att2']: 2,
method1: function () {
console.log('我是方法1');
},
['method2']: function () {
console.log('我是方法2');
}
}
由此可见,在对象里面创建那种特殊变量的方式只有两种
xxx:值/方法
[‘xxx’]:值/方法
而创建的地点分两种,在对象声明的时候就创建和声明好后添加
(1)声明时创建就是
let obj = {
xxx:值/方法
['xxx']:值/方法
}
(2)声明好后添加
let obj = {}
obj.xxx
obj.['xxx']
实际上使用obj这里的特殊变量也就只有两种方式
obj.xxx
obj['xxx']
这就是在对象里面创建函数和方法的全部基本原型,之后的所以变式都是在这个基础上进化而来的。只要把握好上面这两个在对象里声明属性和方法的方式,以及如何使用就能抓住本质。
让我们进一步拓展两种ES6的声明属性和方法的方式
声明属性的方式
let att = 1;
let obj = {
att,
}
console.log(obj.att);
声明方法的方式
let method = function () {
console.log('我是方法');
}
let obj = {
method,
}
obj.method()
放的变量里存的是基本数据类型就是属性
放的变量里存的是函数就是方法
以上是es6关于变量添加属性和方法的新语法,本质上是为了让程序员更快乐的开发,少写代码。
接下来我们再看一个特殊的添加方法的方式
let obj = {
method1() {
console.log('11');
},
['method2']() {
console.log('22');
}
}
obj.method1()
obj['method2']()
我们曾说,在对象里面创建那种特殊的变量就两种方式
let obj = {
xxx:值/方法
['xxx']:值/方法
}
如果这两种指向的是方法那就是
let obj = {
method1:funtion(){
}
['method2'] : funtion(){
}
而这种写法就是把上面的function去掉,同时去掉冒号,是一种新语法,效果完全相同
let obj = {
method1() {
console.log('11');
},
['method2']() {
console.log('22');
}
}
//调用的两种形式
obj.method1()
obj['method2']()
有了这些知识的铺垫,再去看如何使用Symbol.hasInstance就一目了然了。
Symbol.hasInstance是一个Symbol类型的值。
Symbol类型的值和字符串类似。
so我们当然可以这样写
class MyClass {
[Symbol.hasInstance](foo) {
return foo instanceof Array;
}
}
[1, 2, 3] instanceof new MyClass() // true
其实这和
let obj = {
['method2']() {
console.log('22');
}
}
的写法几乎是完全一致的,
Symbol.hasInstance 作为一个内置,是Symbol值,且和字符串性质相似,我们这样写完全没问题。
class MyClass {
[Symbol.hasInstance](foo) {
return foo instanceof Array;
}
}
[1, 2, 3] instanceof new MyClass() // true
so,接下来你所需要知道的就是。
当其他对象在使用instanceof运算符的时候
会自动的调用Symbol.hasInstanceof这个方法,把前面的算子(instanceof前面的那个东西)
这里是[1,2,3],自动的作为参数放入方法中。
new Myclass() 创建了一个实例对象

引用阮一峰大佬的一句话。
上面代码中,MyClass是一个类,new MyClass()会返回一个实例。该实例的Symbol.hasInstance方法,会在进行instanceof运算时自动调用,判断左侧的运算子是否为Array的实例。
下面是阮一峰大佬给的其他例子
这是连接
https://es6.ruanyifeng.com/#docs/symbol#%E5%86%85%E7%BD%AE%E7%9A%84-Symbol-%E5%80%BC

好的,本次就介绍到这里。
谢谢观看。
本文详细介绍了Symbol的基本概念,创建方式,为何不使用字面量,以及其在避免命名冲突中的作用。通过实例演示如何利用Symbol为对象添加不重复的方法,并深入讲解了Symbol.hasInstance的原理和用法。
132





