es6学习笔记(七)

Symbol原始数据类型

1. 概述

  • ES6 引入的一种新的原始数据类型Symbol,表示独一无二的值。
    let s = Symbol();
    typeof s;  //'symbol'
    
  • Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
    let s1 = Symbol('foo');
    let s2 = Symbol('bar');
    
    s1 //Symbol(foo)
    s2 //Symbol(bar)
    
  • Symbol函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。
    // 没有参数的情况
    let s1 = Symbol();
    let s2 = Symbol();
    
    s1 === s2 // false
    
    // 有参数的情况
    let s1 = Symbol('foo');
    let s2 = Symbol('foo');
    
    s1 === s2 // false
    
  • Symbol 值不能与其他类型的值进行运算,会报错。
  • 但是,Symbol 值可以显式转为字符串。
  • 另外,Symbol 值也可以转为布尔值,但是不能转为数值

2.作为属性名的 Symbol

  • 由于每个Symbol值都不相等,所以其可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。可以防止某一个键被不小心改写或覆盖。
  • 注意,Symbol 值作为对象属性名时,不能用点运算符。
    let mySymbol = Symbol();
    
    // 第一种写法
    let a = {};
    a[mySymbol] = 'Hello!';
    
    // 第二种写法
    let a = {
     [mySymbol]: 'Hello!'
    };
    
    // 第三种写法
    let a = {};
    Object.defineProperty(a, mySymbol, { value: 'Hello!' });
    
    // 以上写法都得到同样结果
    a[mySymbol] // "Hello!"
    
    const mySymbol = Symbol();
    const a = {};
    
    a.mySymbol = 'Hello!';
    a[mySymbol] // undefined
    a['mySymbol'] // "Hello!"
    
    
    //在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中
    let s = Symbol();
    
    let obj = {
      [s]: function (arg) { ... }
    };
    
    obj[s](123);
    

3.属性名的遍历

  • Symbol 作为属性名,该属性不会出现在for…in、for…of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名。
     //Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值
     const obj = {};
     let a = Symbol('a');
     let b = Symbol('b');
    
     obj[a] = 'Hello';
     obj[b] = 'World';
    
     const objectSymbols = Object.getOwnPropertySymbols(obj);
    
     objectSymbols
     // [Symbol(a), Symbol(b)]
    
  • Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和 Symbol 键名
    let obj = {
      [Symbol('my_key')]: 1,
      enum: 2,
      nonEnum: 3
    };
    
    Reflect.ownKeys(obj)
    //  ["enum", "nonEnum", Symbol(my_key)]
    

4.Symbol.for(),Symbol.keyFor()

  • Symbol.for 重新使用同一个 Symbol 值。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
    let s1 = Symbol.for('foo');
    let s2 = Symbol.for('foo');
    
    s1 === s2 // true
    
  • Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key
    let s1 = Symbol.for("foo");
    Symbol.keyFor(s1) // "foo"
    
    //变量s2属于未登记的 Symbol 值,所以返回undefined
    let s2 = Symbol("foo");
    Symbol.keyFor(s2) // undefined
    

Set和Map数据结构

1. Set

  • Set类似于数组,但是成员的值都是唯一的,没有重复的值
    const s = new Set();
    //通过add方法向Set结构加入成员,Set结构不会添加重复的值
    [2,3,5,4,5,2,2].forEach(x => s.add(x));
    for(let i of s){
    	console.log(i);
    }
    //2 3 5 4
    
  • Set函数接受一个数组作为参数,用来初始化,可以对数组进行去重
    const set = new Set([1,2,3,4,4]);
    [..set]; //[1,2,3,4]
    
    const items = new Set([1,2,3,4,5,5,5,5]);
    items.size //5
    
  • 在 Set 内部,两个NaN是相等
    let set = new Set();
    let a =  NaN;
    let b =  NaN;
    set.add(a);
    set.add(b);
    set //Set {NaN}
    
  • 在 Set 内部,两个对象总是不相等的
  • Set 实例的属性和方法
    //add(value):添加某个值,返回 Set 结构本身
    s.add(1).add(2).add(2);
    
    //返回Set实例的成员总数
    s.size //2
    
    //has(value):返回一个布尔值,表示该值是否为Set的成员
    s.has(1) // true
    s.has(2) // true
    s.has(3) // false
    
    //delete(value):删除某个值,返回一个布尔值,表示删除是否成功
    s.delete(2);
    
    //clear():清除所有成员,没有返回值
    
  • Array.from方法可以将 Set 结构转为数组
    const items = new Set([1, 2, 3, 4, 5]);
    const array = Array.from(items);
    
  • 遍历操作
    (1)keys(),values(),entries()
    //由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致
    
    let set = new Set(['red', 'green', 'blue']);
    //keys():返回键名的遍历器
    for (let item of set.keys()) {
    	console.log(item);
    }
    // red
    // green
    // blue
    
    //values():返回键值的遍历器
    for (let item of set.values()){
    	console.log(item);
    }
    // red
    // green
    // blue
    
    //entries():返回键值对的遍历器
    for (let item of set.entries()) {
      console.log(item);
    }
    // ["red", "red"]
    // ["green", "green"]
    // ["blue", "blue"]
    
    //可以省略values方法,直接用for...of循环遍历Set
    for (let x of set) {
    	console.log(x);
    }
    
    (2)forEach()
    let set = new Set([1, 4, 9]);
    set.forEach((value, key) => console.log(key + ' : ' + value))
    // 1 : 1
    // 4 : 4
    // 9 : 9
    

2.WeakSet

WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。首先,WeakSet 的成员只能是对象,而不能是其他类型的值。

3.Map

Map类似obj对象键值对的集合,obj的key值只能是字符串,但是map“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。

  • 含义和基本用法
    const m = new Map();
    const o = {p: 'Hello World'};
    
    m.set(o, 'content')
    m.get(o) // "content"
    
    m.has(o) // true
    m.delete(o) // true
    m.has(o) // false
    
  • 实例的属性和操作方法
    (1)size属性返回 Map 结构的成员总数
    (2)set(key, value),set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。
    let map = new Map()
    .set(1, 'a')
    .set(2, 'b')
    .set(3, 'c');
    
    (3)get(key) get方法读取key对应的键值,如果找不到key,返回undefined
    (4)has(key) has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
    (5)delete(key) delete方法删除某个键,返回true。如果删除失败,返回false。
    (6)clear() clear方法清除所有成员,没有返回值
  • 遍历方法
    (1)keys():返回键名的遍历器。
    (2)values():返回键值的遍历器。
    (3)entries():返回所有成员的遍历器。
    (4)forEach():遍历 Map 的所有成员。

4.WeakMap

WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。
WeakMap的键名所指向的对象,不计入垃圾回收机制。

5.与数组的对比

  • Map与Array的对比
    //数据结构横向对比:增、删、改、查
    let map = new Map();
    let array = [];
    
    //增
    map.set('t',1);
    array.push({t:1});
    
    //查
    let map_exist = map.has('t');
    let array_exist = array.find(item =>item.t);
    
    //改
    map.set('t',2);
    array.forEach(item => item.t?item.t=2:' ')
    
    //删
    map.delete('t');
    let index = array.findIndex(item => item.t);
    array.splice(index,1);
    
  • Set与Array的对比
    let set = new Set();
    let array = [];
    
    //增
    set.add({t:1});
    let array = [];
    
    //查
    let set_exist = set.has({t:1});
    let array_exist = array.find(item =>item.t);
    
    //改
    set.forEach(item => item.t? item.t=2:'');
    let array_exist = array.find(item => item.t?item.t=2:' ');
    
    //删
    set.forEach(item => item.t?set.delete(item):' ');
    let index = array.findIndex(item => item.t);
    array.splice(index,1);
    

6.与Object的对比

  • 与Object的对比
    let item = {t:1};
    let map = new Map();
    let set = new Set();
    let obj = {};
    
    //增
    map.set('t',1};
    set.add(item);
    obj['t'] = 1;
    
    //查
    map.has('t');
    set.has(item);
    't' in obj
    
    //改
    map.set('t',2);
    item.t=2;
    obj['t']=2;
    
    //删
    map.delete('t');
    set.delete(item);
    delete obj ['t'];
    

猜你喜欢

转载自blog.csdn.net/weixin_43756060/article/details/84636403
今日推荐