JavaScriptES6(二)

本文介绍了ES6新增的数据类型Symbol在避免属性名冲突、创建私有变量及模块化中的应用,以及Set和Map数据结构的特性、操作和实际使用场景,包括Set的去重、遍历和集合操作,以及Map的键值对处理和 WeakSet的弱引用特性。
摘要由CSDN通过智能技术生成

一、Symbol: 

 ES5中提供了6种数据类型分别是:undefined、null、boolean、string、number、object。ES6中新增了一种数据类型Symbol来表示唯一的值,每个创建的Symbol都是唯一的,这样在实际运用中可以创建一些唯一的属性及定义私有变量。例如:

  let s1 = Symbol; //直接创建
           let s2 = Symbol('mySymbol'); //传入字符串创建

1、目前前端项目都会采用模块化构建,为了防止对象属性名被覆盖,可以通过symbol来定义属性名;例如:

 //a.js
            const NAME = Symbol('name')
            let obj = {
                [NAME]:'张三',
                age: 20
            }
            export default obj;
            //b.js
            import Obj from './a.js'
            const NAME = Symbol('name');
            obj[NAME] = '李四';
            console.log(obj); //{age:20,Symbol():'张三',Symbol():'李四'}

2、利用Symbol作为属性名,属性名不会被Object.keys()、Object.getOwnPropertyNames()、for...in循环返回。例如:

let obj = {
                [Symbol()]:'张三',
                age: 20,
                height:'178com'       
            }
            for(let key in obj){
                console.log(key);
            }
            let keys = Objects.keys(obj);
            console.log(keys); //输出:'age','height'
            console.log(Object.getOwnPropertyNames(obj)); //输出:'age','height'

3、可以在类里利用Symbol来定义私有属性及方法。例如:

  let People = (function(){
                let name = Symbol("name");
                class People {
                    constructor(yourName) { //构造函数
                        this[name] = yourName
                    }
                    sayName() {
                        console.log(this[name])
                    }
                }
                return People;
            })();
            let zhangsan = new People("张三");
            console.log(zhangsan[Symbol("name")]); //undefined
            zhangsan.sayName(); //张三

二、Set集合:是一种数据结构,结构类似于数组,且没有重复的值。主要用于数组去重,字符串去重。

1、操作方法
        (1)add():添加值,返回Set结构本身

let set = new Set()
                set.add(1);
                console.log(set); 
                set.add(1).add(2).add(1)
                console.log(set) 
                //注:拓展运算符(...)可以将Set值扩展出来
                console.log(...set) 
                console.log([...set])

 (2)delete():删除值,并返回一个boolean 表示是否删除成功

let set = new Set()
                set.add(1).add(2); 
                set.delete(1);  
                console.log(...set) 
                set.delete(3)

 (3)has():判断该值是否存在,并返回一个Boolean

 let set = new Set()
                set.add(1).add(2);
                set.has(1); //true
                set.has(3); //false

 (4)clear():清除所有值。没有返回值

 let set = new Set();
                set.add(1).add(2);
                set.clear
                console.log(set,[...set]); // Set(0){} []

 2、遍历方法:

 (1)由于Set只有键值没有键名,也可以说键和值是同一个(键、值相同,可以省略) ,所keys和values返回值相同

   let set = new Set()
                set.add(1).add(2).add(3);
                for( let i of set.keys() ){  //keys遍历键
                    console.log(i)
                    }
                
                for(let i of set.values()) { // values遍历值
                  console.log(i)  
                }
                
                set.add('hello').add(world);
                for( let i of set.entries() ){ //打印键值对
                  console.log(i)  


  (2)forEach()

let set = new Set();
                set.add('hello').add('world');
                set.forEash( ( key, val ) => {
                    console.log(key + '||' + val)
                })  

(3)Set可以接受一个数组作为参数

let arr = [ '小红', '小明', '小强', '小明' ];
                let set = new Set(arr);
                console.log(...set)

 (4)Set实现并集与交集

 let arr = [ 4, 5, 6 ];
                let list = [ 5, 6, 7 ];
                let setA = new Set(arr);
                let setB = new Set(list);
                
                //并集 :集合A 与 集合B 的并集 A U B
                let bj= new Set([ ...setA, ...setB ])
                console.log(bj)
                // 返回Set结构 Set(4) {4,5,6,7}
                
                //交集:集合A 与 集合B 的交集 A ∩ B
                let jj = new Set([...setA].filter(val => setB.has(val))) //通过filter拿到符合条件的值
                console.log(jj)

 3、WeakSet:只能是对象的集合,而不能是任何类型的任意值。WeakSet集合中对象的引用为弱引用。如果没有其他的对WeakSet中对象的引用,那么这些对象会被当成垃圾回收掉。这也意味着WeakSet中没有存储当前对象的列表。正因为这样,WeakSet 是不可枚举的。

即WeakSet中对对象的引用不会被考虑进垃圾回收机制,即只要没有其他的对象引用该对象,则该对象就会被回收,而不管它在不在 WeakSet.

 (1)WeakSet 支持 add,has 和 delete 方法,但不支持 size 和 keys(),并且不可迭代。

 let jack = {name: "jack"};
            let weakSet = new WeakSet();
            weakSet.add(jack, 22);
            console.log( weakSet.has(jack) ); // true
            weakSet.delete(jack);
            console.log( weakSet );  // WeakSet {}

 (2)WeakSet 的应用场景/好处:

用于存储DOM节点,而不用担心这些节点从文档移除时会引发内存泄露
                

三、Map集合:

JavaScript的对象(Object),本质上是键值对的集合(Hash结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。

为了解决这个问题,ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。

 ES6中的Map类型是一种储存着许多键值对的有序列表,其中的键名和对应的值支持所有的数据类型。键名的等价性判断是通过调用Object.is()方法实现的,所以数字5与字符串"5"会被判定为两种类型,可以分别作为独立的两个键出现在程序中,这一点与对象不一样,因为对象的属性名总会被强制转换成字符串类型。

注意:有一个例外,Map集合中将+0和-0视为相等,与Object.is()结果不同
      如果需要“键值对”的数据结构,Map比Object更合适,具有极快的查找速度

1、属性:size  返回Map中的元素个数

 2、基本方法:

(1)set(): 给Map添加数据,返回添加后的Map (给已存在的键赋值会覆盖掉之前的值)
(2)get(): 获取某个key的值,返回key对应的值,没有则返回undefined

(3)has(): 检测是否存在某个key,返回布尔值、

(4)delete(): 删除某个key及其对应的value,返回布尔值,成功:true; 失败:false

(5)clear(): 清除所有的值,返回 undefined

                    let map = new Map();
                    map.set("name", "huochai");
                    map.set("age", 25);
                    console.log(map.size); // 2
                    console.log(map.has("name")); // true
                    console.log(map.get("name")); // "huochai"
                    console.log(map.has("age")); // true
                    console.log(map.get("age")); // 25
                    map.delete("name");
                    console.log(map.has("name")); // false
                    console.log(map.get("name")); // undefined
                    console.log(map.size); // 1
                    map.clear();
                    console.log(map.has("name")); // false
                    console.log(map.get("name")); // undefined
                    console.log(map.has("age")); // false
                    console.log(map.get("age")); // undefined
                    console.log(map.size); // 0

  2、遍历方法:

注意:Map的遍历顺序就是插入顺序

 (1)keys(): 获取Map的所有key

(2)values(): 获取Map的所有值

(3)entries(): 获取Map所有成员

 (4)forEach():遍历Map的所有成员

const map = new Map([
              ['F', 'no'],
              ['T',  'yes'],
            ]);
            
            for (let key of map.keys()) {
              console.log(key);
            }
            // "F"
            // "T"
            
            for (let value of map.values()) {
              console.log(value);
            }
            // "no"
            // "yes"
            
            for (let item of map.entries()) {
              console.log(item[0], item[1]);
            }
            // "F" "no"
            // "T" "yes"
            
            // 或者
            for (let [key, value] of map.entries()) {
              console.log(key, value);
            }
            // "F" "no"
            // "T" "yes"
            
            // 等同于使用map.entries()
            for (let [key, value] of map) {
              console.log(key, value);
            }
            // "F" "no"
            // "T" "yes"

 3、转为数组

 Map结构转为数组结构,比较快速的方法是使用扩展运算符(...)

const map = new Map([
                  [1, 'one'],
                  [2, 'two'],
                  [3, 'three'],
                ]);
                
                [...map.keys()]
                // [1, 2, 3]
                
                [...map.values()]
                // ['one', 'two', 'three']
                
                [...map.entries()]
                // [[1,'one'], [2, 'two'], [3, 'three']]
                
                [...map]
                // [[1,'one'], [2, 'two'], [3, 'three']]

4、结合数组的map方法、filter方法,可以实现 Map 的遍历和过滤  

const map0 = new Map()
                  .set(1, 'a')
                  .set(2, 'b')
                  .set(3, 'c');
                
                const map1 = new Map(
                  [...map0].filter(([k, v]) => k < 3)
                );
                // 产生 Map 结构 {1 => 'a', 2 => 'b'}
    
                const map2 = new Map(
                  [...map0].map(([k, v]) => [k * 2, '_' + v])
                    );
                // 产生 Map 结构 {2 => '_a', 4 => '_b', 6 => '_c'}

5、forEach()

  const map = new Map([[1, 'one'],[2, 'two'],[3, 'three']]);
                map.forEach((value,key,map)=>{
                    //one 1 {1 => "one", 2 => "two", 3 => "three"}
                    //two 2 {1 => "one", 2 => "two", 3 => "three"}
                    //three 3 {1 => "one", 2 => "two", 3 => "three"}
                    console.log(value,key,map);
                })

6、WeakMap:是弱引用Map集合,也用于存储对象的弱引用。WeakMap集合中的键名必须是一个对象,如果使用非对象键名会报错;集合中保存的是这些对象的弱引用,如果在弱引用之外不存在其他的强引用,引擎的垃圾回收机制会自动回收这个对象,同时也会移除WeakMap集合中的键值对。但是只有集合的键名遵从这个规则,键名对应的值如果是一个对象,则保存的是对象的强引用,不会触发垃圾回收机制

 (1)使用WeakMap集合

 ES6中的WeakMap类型是一种存储着许多键值对的无序列表,列表的键名必须是非null类型的对象,键名对应的值则可以是任意类型。WeakMap的接口与Map非常相似,通过set()方法添加数据,通过get()方法获取数据 

let map = new WeakMap(),
              element = document.querySelector(".element");
                map.set(element, "Original");
                let value = map.get(element);
                console.log(value); // "Original"
                element.parentNode.removeChild(element); // 移除元素
                element = null; // 该WeakMap在此处为空

  WeakMap集合不支持size属性,从而无法验证集合是否为空;

  (2)WeakMap集合支持的方法
           has()方法可以检测给定的键在集合中是否存在;
      delete()方法可移除指定的键值对。
         

  let map = new WeakMap(),
            element = document.querySelector(".element");
            map.set(element, "Original");
            console.log(map.has(element)); // true
            console.log(map.get(element)); // "Original"
            map.delete(element);
            console.log(map.has(element)); // false
            console.log(map.get(element)); // undefined

 (3)WeakMap集合的用途

    A、储存DOM元素

 let myElement = document.getElementById('btn');
                let myWeakmap = new WeakMap();
                myWeakmap.set(myElement, {timesClicked: 0});
                myElement.addEventListener('click', function() {
                let logoData = myWeakmap.get(myElement);
                logoData.timesClicked++;
                console.log(logoData.timesClicked)
                }, false);

代码中,myElement是一个DOM节点,每当发生click事件,就更新一下状态。我们将这个状态作为键值放在WeakMap里,对应的键名就是myElement。一旦这个DOM节点删除,该状态就会自动消失,不存在内存泄漏风险       

  B、注册监听事件的listener对象,就很合适用WeakMap实现

 const listener = new WeakMap();
    
                listener.set(element1, handler1);
                listener.set(element2, handler2);
                
                element1.addEventListener('click', listener.get(element1), false);
                element2.addEventListener('click', listener.get(element2), false);

 监听函数放在WeakMap里面。一旦 DOM 对象消失,跟它绑定的监听函数也会自动消失

 C、部署私有属性

  我们创建对象的时候,通常写一个构造函数

function Person(name) {
                        this._name = name;
                    }
                    Person.prototype.getName = function() {
                        return this._name;
                    };

 但这时,创建一个Person 对象的时候,我们可以直接访问name 属性:

const person = new Person("sam")
                    console.log(persn.name)

我们不想让用户直接访问name属性, 直接使用下面的方法将name包装成私有属性

 let Person = (function() {
                        let privateData = new WeakMap();
                        function Person(name) {
                            privateData.set(this, { name: name });
                        }
                        Person.prototype.getName = function() {
                            return privateData.get(this).name;
                        };
                        return Person;
                    }());

                    const person = new Person('json');
                    console.log(person.getName())

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值