es6 Symbol

ES6

Symbol(简单篇)

概念

symbol类型表示的是独一无二的值,常用在定义对象的唯一属性名。

描述为字符串或者是数字。在内存中代表一个唯一的值。

let s1=Symbol('111'); // Symbol(111)
let s2=Symbol('222'); // Symbol(222)
let s3=Symbol.iterator;
let arr=[1,2,3]
console.dir(s1);
console.dir(s2);
console.dir(s3);
console.log(s1===s2);
console.log(arr);
console.log(arr[Symbol.interator])

注意点

不能new

不能参与运算

基础用法

定义很多常量,然后又不希望它们重复。

绝对不可能重复,因为每一个symbol都是不一样的。

高级用法

  1. 定义对象的唯一属性名

  2. 不会被Object.keys和for...in遍历到,所以它起到了私有属性保护的作用。同理,也不会被JSON.stringify到。

  1. 当用symbol去定义对象属性的时候,一定要用中括号 [ ] 语法;(声明、获取、赋值都需要中括号包裹)

let a={};
let s=Symbol(123)
// 给对象添加属性
a[s]='hello'
console.log(a);

// 字面量
let b={
    [s]:'world',
    x:'hello',
}
console.log(b);
console.log(Object.keys(b));

案例

let obj={
    name:'angela',
    age:18,
    gender:1,
    [Symbol('password')]:'123456'
};
console.log(JSON.stringify(obj));

共享容器中的使用

需要有唯一值的,不希望多个字段覆盖的情况

class Cache{
    static data={};
    static set(name,value){
        this.data[name]=value;
    }
    static get(name){
        return this.data[name];
    }
}
let user={
    name:'apple',
    age:18,
    key:Symbol(),
}
let cart={
    name:'apple',
    key:Symbol()
}
Cache.set(user.key,user);
Cache.set(cart.key,cart);
console.log(Cache.data);

扩展

for-in

遍历对象用for-in,for-of不能用在对象上

  • for-in是会遍历到原型链上的属性的;Object.keys()、hasOwnProperty是不会的

for of 和 for in 的区别_前端路上有你有我!-优快云博客_forof和forin的区别

Object.getOwnPropertySymbols

获取此对象的Symbol属性

Object.prototype[Symbol('global')]='global'

let obj={
    a:'hello world',
    b:'hello jsp',
    [Symbol('blue')]:'blue',
    [Symbol('red')]:'red',
}
console.log(obj)
// 遍历不到原型链上的属性的
console.log(Object.getOwnPropertySymbols(obj));
// 获取全部属性
console.log(Reflect.ownKeys(obj));

Object.prototype.a='a'
class User{
    type='people';
    constructor(name){
        this.name=name;
        this[Symbol('site')] = 'houdunren';
    }
    getName(name){
        return this.name;
    }
}
let person= new User('angela');
console.log(person.getName());
console.log(person);
for(key in person){
    console.log('---')
    console.log(key)
    if(person.hasOwnProperty(key)){
        console.log(key)
    }
}

Symbol.for()

Symbol.for是全局的,他首先会去全局搜索有没有这个symbol值,有就直接返回;没有才去创建。Symbol.for有一个登记机制,会在内存中有一个记录。比如,Symbol.for 100次,其实只有一个symbol;但是Symbol 100次,会有100个symbol。

全局定义的symbol可以通过Symbol.keyFor(symbol_var)获取到它的描述

es6 Symbol.for(),Symbol.keyFor()_歪脖先生的博客-优快云博客_symbol.for

ES6入门之Symbol - 珍真小心 - 博客园

Symbol类型

前置知识

js数据类型:

原始类型

null undefined boolean string number Symbol bigint

对象类型

标准普通对象:大括号包裹的

标准特殊对象:数组 正则 date error

非标准特殊对象:new Number() ->原始类型所对应的对象类型实例

函数对象:function

概念

Symbol:唯一值

不能被new执行的:与类的区别,创建实例,通过new来执行

例子:

运用场景

语法:用 [] 包裹

场景:

  1. 给对象设置唯一值的属性

获取对象属性的一些方法:

for-in:遍历不到Symbol;会把原型上可枚举(公共)的属性迭代到,所以性能就比较差;

Object.key:获取自身的私有属性,非Symbol的

Object.getOwnPropertySymbols:获取对象的Symbol属性

Reflect.ownKeys:对象的Symbol+非Symbol属性

  1. 公共状态管理:行为标识

Symbol.for

symbol全局注册表的概念

迭代器

打印一下Symbol

.for .keyFor

.match .matchAll 跟正则匹配相关的


迭代器规范

  1. 只要部署了interator接口机制就可以完成for-of循环遍历,for-of循环的底层机制是用的iterator

  2. 迭代器规范要求需要有一个next方法

有Symbol.iterator属性的我们就说具备迭代器规范的

for-of的原理:手写Symbol.iterator

  1. for-of循环开始就会调Symbol.iterator函数,而这个函数就是按照Iterator规范来设计的

  2. 迭代器规范是这样,Symbol.iterator要返回一个对象,该对象要具有next方法,每次for-of都会执行这个方法;而next也会返回一个对象,该对象有2个固定的属性,done表示迭代是否完成,value表示当前迭代返回的结果

    let obj={
        name:'angela',
        age:18,
        [Symbol('abc')]:'abc',
    }
    Object.prototype[Symbol.iterator]=function(){
        let index = 0;
        const self=this;
        // 这是获取非Symblo属性
        // const keys=Object.keys(self);
        // 这是获取所有属性
        const keys=Reflect.ownKeys(self);
        return {
            next(){
                if(index>keys.length-1){
                    return {
                        done:true,
                        value:undefined,
                    }
                }
                return{
                    done:false,
                    value:self[keys[index++]]
                }
            }
        }
    }
    for(let abc of obj){
        console.log(abc);
    }

生成器

生成器对象

概念:前面加 * 号的就是generator生成器函数,它会返回一个迭代器对象。并不会执行函数体。调用next才开始执行函数体,遇到yield则停止。

function* generator(){
    console.log('1--')
    yield 10;
    console.log('2--')
    yield 20;
    console.log('3--')
    yield 30;
}
let iter=generator()
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());

for await of

[Symbol.asyncIterator]函数必须要async修饰

yield返回一个promise实例,await等待其resolve

循环处理promise,适合串行需求

2个要注意的地方:

  1. 立即执行函数要加async,因为里面有for await;

  2. generator函数要加async,因为其函数体中有return new Promise

function func1(){
    return new Promise(resolve=>{
        setTimeout(()=>{
            resolve()
        },1000)
    })
}
function func2(){
    return new Promise(resolve=>{
        setTimeout(()=>{
            resolve()
        },2000)
    })
}
function func3(){
    return new Promise(resolve=>{
        setTimeout(()=>{
            resolve()
        },3000)
    })
}
let obj={};
obj[Symbol.asyncIterator]=async function*(){
    console.log('1 start');
    // 等待promise实例成功
    yield func1();
    console.log('2 start');
    yield func2();
    console.log('3 start');
    yield func3();
};
(async function(){
    for await(let value of obj){
    }
})();

Symbol.hasInstance

instanceof的原理

instanceof的表现:

x instanceof y: instanceof会沿着原型链往上找,看有没有y这个原型

其实这也就是 instanceof 原理是什么:

obj instanceof Ctor => 会执行Ctor[Symbol.hasInstance](obj),会执行这个方法,传obj进来;

没有这个方法才会按原型链去找

目的:避免原型重定向,只允许实例是我才行

class Fn{
    constructor(){
        this.x = Symbol.for('x');
    }
    static [Symbol.hasInstance](obj){
        return obj.x && obj.x === Symbol.for('x');
    }
}
let fn = new Fn();
// console.log(Reflect.ownKeys(fn));
// console.log(Object.getOwnPropertySymbols(fn));
console.log(fn instanceof Fn); // true


let arr=[10,20,30];
// arr.__proto__ = Fn.prototype;
Object.setPrototypeOf(arr,Fn.prototype);
console.log(arr instanceof Fn); // true

Symbol.toPrimitive

前言:

defineProperty和proxy,面试官可能会问你2.0和3.0的区别

toString、valueOf:对象转换为原始类型经历了哪些步骤。它会有更深层次的问法。

对象转换为字符串(数字)经历的步骤

== : 左边是对象

  1. 首先看对象 [Symbol.toPrimitive] 这个属性,有则按这个处理;

  2. 如果没有则看 valueOf,验证是否是原始类型

  3. 如果不是原始类型,则看toString 将其转换为字符串

  4. 将字符串转换为数字

let a ={
    i:0,
    [Symbol.toPrimitive](hint){
        console.log(hint);
        return ++this.i;
    }
}
if(a ==1 && a==2 & a==3){
    console.log('ok');
}

js面试题:a==1&&a==2&&a=3的两个思路_imoo的笔记-优快云博客_a===1&&a===2&&a===3

Symbol.toPrimitive - JavaScript | MDN

Symbol.toStringTag

  1. 先看[Symbol.toStringTag]

  2. 没有则调用内置Class

class Fn{
    constructor(){
    }
    get[Symbol.toStringTag](){ return 'Fn' }
}
// Fn.prototype[Symbol.toStringTag]=function(){ return 'Fn' };
let fn = new Fn();
console.log(fn.toString());
console.log(Object.prototype.toString.call(fn));
let n = new Number(12);
console.log(Object.prototype.toString.call(n));
let m = true;
console.log(Object.prototype.toString.call(''));

通过Object.prototype.toString - 精确判断对象的类型 - 李小菜丶 - 博客园

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值