es6-symbol之知名符号

半腔热情 提交于 2020-01-29 11:17:45

知名符号(公共、具名)是一些具有特殊含义的共享符号,通过Symbol的静态属性得到
ES6延续了ES5的思想:减少魔法,暴露内部实现!
因此ES6用知名符号暴露了某些场景的内部实现。

  1. Symbol.hasInstance
    该符号用于定义构造函数的静态成员,它将影响instanceof的判定
obj instanceof A
//等效于
A[Symbol.hasInstance](obj) //Function.prototype[Symbol.hasInstance]

例:

function A() {

}


const obj = new A();
console.log(obj instanceof A);      //true
console.log(A[Symbol.hasInstance](obj));//true

这里有了Symbol.hasInstance这个静态属性,我们便可以参与instanceof的判定的内部实现,这次为了让它判断的时候返回false。

function A() {

}

Object.defineProperty(A, Symbol.hasInstance, {
//这里甚至可以写一些打印的语句,在执行instanceof判断的时候也是会打印到控制台的。
    value: function(obj) {
        return false;
    }
})
const obj = new A();
console.log(obj instanceof A);      //false
console.log(A[Symbol.hasInstance](obj));     //false
  1. Symbol.isConcatSpreadable
    该知名符号会影响数组concat 方法
const arr = [3];
const arr2 = [5, 6, 7, 8];

//arr2[Symbol.isConcatSpreadable] = false;

const result = arr.concat(3);
const result1 = arr.concat(56, arr2);

console.log(result);
console.log(result1);

这里的concat可以有两种可能的方式,一个是将数组arr2作为一个元素与arr数组连接组成result1另一个是将数组arr2展开作为多个元素与arr数组连接。这里arr2[Symbol.isConcatSpreadable] = false;concat就会以第一种方式不展开数组,而不写(默认为true)或指定arr2[Symbol.isConcatSpreadable] = true;则为第二种方式,将arr2展开。

这个静态方法还可以用于对象

const arr = [3];
const obj = {
    0: 2,
    1: 3,
    length: 2,
   // [Symbol.isConcatSpreadable]: true
}
const result1 = arr.concat(56, obj);
console.log(result1);  // [3, 56, {…}]       //(4) [3, 56, 2, 3]

在这里插入图片描述
默认情况,对象不会展开分割是作为一个元素连接到数组;如果在对象里加这样[Symbol.isConcatSpreadable]: true一个属性,就会将对象里有连续索引的项展开。
这里受到 length属性的影响,可以在控制台,多试几个情况体验它的特点。
3. Symbol.toPrimitive 该知名符号会影响类型转换的结果

const obj = {
    a: 1,
    b: 2
}
//obj[Symbol.toPrimitive] = function() {
    return 2;
}
console.log(obj.valueOf()); //拿到对象的基本类型  {a: 1, b: 2}
console.log(obj.toString()); //[object Object]
console.log(obj + 123); //[object Object]123
console.log(obj * 123); //NaN

如果加上这一语句obj[Symbol.toPrimitive] = function(){ retrun 2;}控制台输出结果将会变成如下情形:
在这里插入图片描述
例2

class Temperature {
    constructor(degree) {
            this.degree = degree;
        }
        // [Symbol.toPrimitive](type) {
        //     console.log(type)
        //     if (type === "default") {
        //         return this.degree + "摄氏度";
        //     } else if (type === "number") {
        //         return this.degree;
        //     } else if (type === "string") {
        //         return this.degree + "℃"
        //     }
        // }
}
const t = new Temperature(30);
console.log(t + "!"); //[object Object]!
console.log(t / 2); //NaN
console.log(String(t)); //[object Object]

这是一个温度的类,默认是调用valueOf()toString类型转换输出。当给这个类添加了


         [Symbol.toPrimitive](type) {
        console.log(type)
           if (type === "default") {
               return this.degree + "摄氏度";
             } else if (type === "number") {
       return this.degree;
           } else if (type === "string") {
              return this.degree + "℃"
            }
       }

这样我们就可以干预到类型转换,输出结果如下:
在这里插入图片描述
4. Symbol.toStringTag 该知名符号会影响Object.prototype.toString 的返回值

class Person {
// [Symbol.toStringTag] = "Person"
}

const p = new Person();
const arr = [325, 35, 89];
console.log(p.toString());
console.log(arr.toString());
console.log(Object.prototype.toString.apply(p));
console.log(Object.prototype.toString.apply(arr));

在这里插入图片描述
这里arr.toString是Array底层更改了toString实现,要使用apply改变this指向运用Object.prototype.toString的方法,来验证结果。
当启用了[Symbol.toStringTag] = "Person"就会得到如下结果:

在这里插入图片描述
此处只列举了4 个还有其他知名符号,可以去学习。
这样我们就可以使用一些Symbol静态方法(知名符号),来参与JS的底层实现。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!