你了解es6的符号吗?

符号概述

符号是什么?

符号是ES6新增的一个数据类型,它没有字面量,只能通过使用函数 Symbol(符号描述)来创建

符号有什么特点?

  • 没有字面量
  • 使用 typeof 得到的类型是 symbol
  • 每次调用 Symbol 函数得到的符号永远不相等,无论符号名是否相同
  • 符号可以作为对象的属性名存在,这种属性称之为符号属性
    • 开发者可以通过精心的设计,让这些属性无法通过常规方式被外界访问
    • 符号属性是不能枚举的,因此在 for-in 循环中无法读取到符号属性,Object.keys 方法也无法读取到符号属性
    • Object.getOwnPropertyNames 尽管可以得到所有无法枚举的属性,但是仍然无法读取到符号属性
    • ES6 新增 Object.getOwnPropertySymbols 方法,可以读取符号(详见下一节的案例)
  • 符号无法被隐式转换,因此不能被用于数学运算、字符串拼接或其他隐式转换的场景,但符号可以显式的转换为字符串,通过 String 构造函数进行转换即可,console.log 之所以可以输出符号,是它在内部进行了显式转换
let symbol = Symbol('测试符号');
console.log(String(symbol)) // Symbol(测试符号)

符号解决了什么?

符号设计的初衷,是为了给对象设置私有属性
私有属性:只能在对象内部使用,外面无法使用

符号的使用

创建一个构造函数飞机,飞机有攻击方法,会扣除地方血量,血量会在一个范围内浮动

let Plane = (function () {
    let random = Symbol('random');
    return class {
        constructor() {
            let random = Symbol('random')
        }
        gongji() {
            console.log(`对方掉血${this[random](10, 20)}`)
        }
        [random](min, max){
            return parseInt(Math.random() * (max - min)) + min
        }
    }
})() 
let p1 = new Plane();
p1.gongji()

如何获取符号属性

如果真的需要获取一个对象的符号属性的话,我们可以使用object.getOwnPropertySymbols()获取

let Plane = (function () {
let random = Symbol('random');
return class {
    constructor() {

        let random = Symbol('random')
    }
    gongji() {
        console.log(`对方掉血${this[random](10, 20)}`)
    }
    [random](min, max) {
        return parseInt(Math.random() * (max - min)) + min
    }
}
})()
let p1 = new Plane();
let symbolArr = Object.getOwnPropertySymbols(p1.__proto__);
console.log(symbolArr); // [Symbol(random)]
console.log(p1[symbolArr[0]](10, 20)); // 11

共享符号

当我们想在两个不同的js文件中使用同一个符号的时候,我们可以使共享符号

let sym1 = Symbol.for('a');
let sym2 = Symbol.for('a');
console.log(sym1 === sym2); // true

共享符号的实现

let symbolFor = (function () {
    let obj = {}
    return function (str) {
        console.log(str)
        if (obj[str]) {
            return obj[str]
        } else {
            obj[str] = Symbol(str);
            return obj[str]
        }
    }
})()
console.log(symbolFor('q') == symbolFor('q'))

知名符号

知名符号存在的意义是什么?

知名符号可以减少一个语言中的魔法,

function A() {};
let a = new A();
console.log(a instanceof A);

instanceof的内部实现我们是无法参与的,这就是魔法,当一个语言成熟的时候,应该减少魔法,可以让开发者参与到他的内部实现,知名符号就提供了这个功能。

function A() {};
let a = new A();
Object.defineProperty(A, Symbol.hasInstance, {
    value: () => false
})
console.log(a instanceof A);

我们可以通过改变Symbol.hasInstance的值来改变instanceof的内部实现,这个操作只能通过Object.defineProperty完成,不可以直接赋值

其他知名符号

Symbol.isConcatSpreadable决定了当合并数组的时候,是将数组拆开还是作为一个整体被合并

let arr1 = [3];
let arr2 = [5, 6, 7, 8];
arr2[Symbol.isConcatSpreadable] = true;
const result = arr1.concat(56, arr2);
console.log(result); // [3, 56, 5, 6, 7, 8]
let arr1 = [3];
let arr2 = [5, 6, 7, 8];
arr2[Symbol.isConcatSpreadable] = false;
const result = arr1.concat(56, arr2);
console.log(result); // [3, 56, [5, 6, 7, 8]]

这个符号还可以作用于对象

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

参与类型转换内部实现

Symbol.toPrimitive符号可以修改数据类型转换的结果

class Temperature {
    constructor(degree) {
        this.degree = degree;
    }
    [Symbol.toPrimitive](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 + "!"); // 30摄氏度!
console.log(t / 2); // 15
console.log(String(t)); // 30℃

参与toString的内部实现

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

const p = new Person();
const arr = [32424, 45654, 32]
console.log(Object.prototype.toString.apply(p)); // [object Person]
console.log(Object.prototype.toString.apply(arr)); // [object Array]
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值