ES6新引入的类型Symbol详解以及示例

ES6引入的新的原始数据类型Symbol,表示独一无二的值,它是js中的第7种数据类型,是一种类似于字符串的数据类型。
Symbol特点:
1、Symbol的值是唯一的,用来解决命名冲突的问题。
2、Symbol值不能与其他数据进行运算。
3、Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名。然后遍历。

如何创建?

可以使用函数创建。
let s = Symbol('demo');
或者
let s1 = Symbol.for('demo');
使用for函数可以得到某个字符串唯一的symbol值,例如下面的比较是相等的。
let s2 = Symbol.for('demo');
s1 === s2 返回的就是true。

Symbol内置的值

用做对象的属性。通过对这些内置值的设置,来改变对象在某些特定场景下的表现。
最常用的有:

  • Symbol.hasInstance
    在使用instanceof操作符时调用。
class Person{
    static [Symbol.hasInstance](param){
        console.log(param);
        console.log('我被用来检查类型了')
        return false;
    }
}

let obj = {}
console.log(obj instanceof Person) 
  • Symbol.isConcatSpreadable
    使用concat来合并两个数组的时候,js会默认将数组内的元素展开然后合并为一个数组返回(原数组不变),这个行为es6以后可以使用Symbol.isConcatSpreadable改变,将其置为false就可以将数组作为一整个对象合并到过去。
let animals = ['cat','dog','panda']
let fruit = ['apple','pear']
fruit[Symbol.isConcatSpreadable] = true
console.log(animals.concat(fruit))  // 结果是['cat','dog','panda','apple','pear']
fruit[Symbol.isConcatSpreadable] = false
console.log(animals.concat(fruit))  // 结果是['cat','dog','panda', Array(2)]
  • Symbol.iterator
    用于给对象定义迭代方法,这样就可以使用es6中新提供的for...of语法,需要注意的是,自定义的这个迭代器方法,需要按照一定的规范来写,需要返回一个具有next方法的对象,next方法需要返回具有value和done两个属性的对象。done会被用来判断什么时候结束迭代。
const banji = { 
  name: "终极一班", 
  stus: [ 'xiaoming', 'xiaoning', 'xiaotian', 'knight' ],
  [Symbol.iterator]() {
    // 索引变量 
    let index = 0; 
    // 保存this 
    let _this = this; 
    return { 
      next: function() { 
        if (index < _this.stus.length) {
           const result = { value: _this.stus[index], done: false };
           // 下标自增
           index++; 
           // 返回结果 
           return result; 
        } else { 
           return { value: undefined, done: true }; 
        } 
      } 
    }; 
  }
}
// 遍历这个对象 
for (let v of banji) {
   console.log(v); 
}
  • Symbol.match
    一个在调用 String.prototype.match() 方法时调用的方法, 直白点说就是如果你定义一个字符串strValue,当你调用strValue.match(ObjectCase),如果ObjectCase这个对象定义了Symbol.match方法时,就会执行这个方法。
let animal = {
    [Symbol.match](str){
        console.log(str)   //打印出字符串 cat
        return str.indexOf('animal');
    }
}
let kitty = "cat"
console.log(kitty.match(animal))    //返回值-1,这里打印出-1
  • Symbol.replace
    一个在调用 String.prototype.replace() 方法时调用的方法,和上面的一样,当一个字符串调用strValue.replace(ObjectCase)时,会去执行ObjectCase中的Symbol.replace方法。
let animalName = {
    /* strValue 会返回调用者本身,replacement为调用repalce方法时传入的第二个参数 */
    [Symbol.replace](strValue, replacement){
        console.log("strValue: " + strValue,"replacement: " + replacement)  //strValue: cat, its name is {params} replacement: {params}
        return strValue.replace("{params}", "kitty")
    }
}
let kitty = "cat, its name is {params}"
console.log(kitty.replace(animalName, "{params}"))  //cat, its name is kitty
  • Symbol.search
    一个在调用 String.prototype.search() 方法时调用的方法,用于在字符串中定位子串,这个也和上面str相关扩展一样直接看示例。
let animalName = {
    /* strValue就是调用者本身  */
    [Symbol.search](strValue){
        console.log(strValue)  //cat, its name is kitty
        return strValue.split("name is")[1]
    }
}
let kitty = "cat, its name is kitty"
console.log(kitty.search(animalName))  //kitty
  • Symbol.split
    一个在调用 String.prototype.split() 方法时调用的方法,用于分割字符串。
let animalName = {
    /* strValue就是调用者本身 */
    [Symbol.split](strValue){
        console.log(strValue)  //cat, its name is kitty
        return strValue.indexOf("name")
    }
}
let kitty = "cat, its name is kitty"
console.log(kitty.split(animalName))  //8
  • Symbol.toPrimitive
    这个方法决定了当一个对象被转换为原始值时的行为。JavaScript引擎在每个类型值的原型上定义了Symbol.toPrimitive方法。这个方法被调用时,会接受一个字符串参数,表示当前运算的模式,一共有三种模式:
    number: 该场景下需要转换成数值.对应操作符:* / -
    string: 该场景下需要转换成字符串,显示使用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();
        }
    }
}
console.log(2 * obj) //246
console.log(3 + obj) //3default
console.log(obj == 'default') //true
console.log(String(obj)) //str
  • Symbol.species
    对象的Symbol.species属性,指向一个构造函数,创建衍生对象时,会使用该属性。这个的主要用途是,有些类库是在基类的基础上修改的,那么子类使用继承的方法时,作者可能希望返回基类的实例,而不是子类的实例。
class MyArray extends Array {
    static get [Symbol.species](){
        return Array;
    }
}
//b,c是a的衍生对象
const a = new MyArray(1,2,3)
const b = a.map(x => x+1)
const c = a.filter(x => x > 0)
//如果没有定义上面的Symbol.species,那么下面的instanceof均返回true
console.log(b instanceof MyArray)   //true
console.log(c instanceof MyArray)   //true
//定义了上面的Symbol.species时,返回值是下面这样
console.log(b instanceof MyArray)   //false
console.log(b instanceof Array)     //true
  • Symbol.toStringTag
    一个在调用 String.prototype.toString() 方法时使用的字符串,用于创建对象描述。在对象上面调用Object.prototype.toString方法时,如果这个属性存在,它的返回值会出现在toString方法返回的字符串中,表示对象的类型。
//第一种写法,注意这里的get关键字是必须的,call方法需要用到get取值器
let animal = {
    get [Symbol.toStringTag](){
        return 'animal'
    }
}
console.log(Object.prototype.toString.call(animal)) // [object animal]
//第二种写法
console.log({[Symbol.toStringTag]: 'tag'}.toString()) // [object tag]
  • Symbol.unscopables
    一个定义了一些不可被 with 语句引用的对象属性名称的对象集合。集合中的属性名称,会在with环境绑定中被排除。
const animal = {
    type: 'animal',
    name: 'kitty'
}
with(animal){
    console.log(type, name) //animal kitty
}
//定义Symbol.unscopables以便在with环境中排除某些属性
animal[Symbol.unscopables] = {
    type: true
}
with(animal){
    console.log(type)   //Uncaught ReferenceError: type is not defined
}

以上这些被称为众所周知的symbols,其实其中很多值并不常用,为了验证这些symbols的准确用法,我搜了很多资料,总算把每一个都亲自验证了一遍。
这里附上一个地址,这里面有特别详细的示例代码,我也是自己费了半天劲儿快验证完的时候才发现这个网址的,白白浪费了好多时间。
Symbol比较全面的示例

另外,之所以要研究这个,主要是最近在学vue3 + typescript,身为一个没太多基础的前端小白,学习的过程中遇到一个知识点可能都会要查半天资料才能弄懂,不过我也乐在其中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,961评论 5 473
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,444评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,009评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,082评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,101评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,271评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,738评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,395评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,539评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,434评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,481评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,160评论 3 317
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,749评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,816评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,038评论 1 256
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,548评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,140评论 2 341

推荐阅读更多精彩内容