第6章 集合

  Map 和 Set 就不说了,很常规的概念,不过Map和Object有点区别的,比如Map可以用一个object作为key。

  这里重点说一下WeakMap。 WeakMap和Map主要有如下几个区别:

  1. WeakMap 只能用Object作为key,不能用基本数据类型比如字符串作为key
  2. WeakMap 中的key是弱引用
  3. WeakMap 没有size

  其中1和3非常好理解,重点就是第2点,也是WeakMap名字的由来。

  无论任何GA,最重要的一点都是要通过对象引用来判断对象是否存活,不过Node中具体实现比较复杂,可以参见《深入浅出Nodejs》第五章。

  Map 的一个最大弊端就是它会导致作为key的对象增加一个引用,因此导致GA无法回收这个对象,如果大量使用object作为Map的key会导致大量的内存泄露。

  WeakMap就是为了解决这个问题,在WeakMap中对作为key的对象是一个弱引用,也就是说,GA在计算对象引用数量的时候并不会把弱引用计算进去。这样当一个对象除了WeakMap没有其他引用的时候就会被GA回收掉。 

集合

/**
 * ECMSCRIPT 6 already have a Set class implementation:
 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
 * We will try to copy  the same functionalities
 * @constructor
 */
function Set() {

    let items = {};

    this.add = function(value){
        if (!this.has(value)){
            items[value] = value;
            return true;
        }
        return false;
    };

    this.delete = function(value){
        if (this.has(value)){
            delete items[value];
            return true;
        }
        return false;
    };

    this.has = function(value){
        return items.hasOwnProperty(value);
        //return value in items;
    };

    this.clear = function(){
        items = {};
    };

    /**
     * Modern browsers function
     * IE9+, FF4+, Chrome5+, Opera12+, Safari5+
     * @returns {Number}
     */
    this.size = function(){
        return Object.keys(items).length;
    };

    /**
     * cross browser compatibility - legacy browsers
     * for modern browsers use size function
     * @returns {number}
     */
    this.sizeLegacy = function(){
        let count = 0;
        for(let key in items) {
            if(items.hasOwnProperty(key))
                ++count;
        }
        return count;
    };

    /**
     * Modern browsers function
     * IE9+, FF4+, Chrome5+, Opera12+, Safari5+
     * @returns {Array}
     */
    this.values = function(){
        let values = [];
        for (let i=0, keys=Object.keys(items); i otherSet.size()){ //{1}
            return false;
        } else {
            let values = this.values();
            for (let i=0; i

set2

let Set2 = (function () {

    const items = new WeakMap();

    class Set2 {

        constructor () {
            items.set(this, {});
        }

        add(value){
            if (!this.has(value)){
                let items_ = items.get(this);
                items_[value] = value;
                return true;
            }
            return false;
        }

        delete(value){
            if (this.has(value)){
                let items_ = items.get(this);
                delete items_[value];
                return true;
            }
            return false;
        }

        has(value){
            let items_ = items.get(this);
            return items_.hasOwnProperty(value);
        }

        clear(){
            items.set(this, {});
        }

        size(){
            let items_ = items.get(this);
            return Object.keys(items_).length;
        }


        values(){
            let values = [];
            let items_ = items.get(this);
            for (let i=0, keys=Object.keys(items_); i otherSet.size()){
                return false;
            } else {
                let values = this.values();
                for (let i=0; i

UsingSets

let set = new Set();

set.add(1);
console.log(set.values()); //outputs [1]
console.log(set.has(1));   //outputs true
console.log(set.size());   //outputs 1

set.add(2);
console.log(set.values()); //outputs [1, 2]
console.log(set.has(2));   //true
console.log(set.size());   //2
console.log(set.sizeLegacy());   //3

set.delete(1);
console.log(set.values()); //outputs [2]

set.delete(2);
console.log(set.values()); //outputs []

Operations

//--------- Union ----------

let setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);

let setB = new Set();
setB.add(3);
setB.add(4);
setB.add(5);
setB.add(6);

let unionAB = setA.union(setB);
console.log(unionAB.values());


//--------- Intersection ----------

let setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);

let setB = new Set();
setB.add(2);
setB.add(3);
setB.add(4);

let intersectionAB = setA.intersection(setB);
console.log(intersectionAB.values());

//--------- Difference ----------

let setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);

let setB = new Set();
setB.add(2);
setB.add(3);
setB.add(4);

let differenceAB = setA.difference(setB);
console.log(differenceAB.values());

//--------- Subset ----------

let setA = new Set();
setA.add(1);
setA.add(2);

let setB = new Set();
setB.add(1);
setB.add(2);
setB.add(3);

let setC = new Set();
setC.add(2);
setC.add(3);
setC.add(4);

console.log(setA.subset(setB));
console.log(setA.subset(setC));

UsingES6Set

let set = new Set();

set.add(1);
console.log(set.values()); //outputs @Iterator
console.log(set.has(1));   //outputs true
console.log(set.size);   //outputs 1

set.add(2);
console.log(set.values()); //outputs [1, 2]
console.log(set.has(2));   //true
console.log(set.size);   //2

set.delete(1);
console.log(set.values()); //outputs [2]

set.delete(2);
console.log(set.values()); //outputs []

let setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);

let setB = new Set();
setB.add(2);
setB.add(3);
setB.add(4);

//--------- Union ----------
let unionAb = new Set();
for (let x of setA) unionAb.add(x);
for (let x of setB) unionAb.add(x);
console.log(unionAb);

//--------- Intersection ----------
let intersection = function(setA, setB){
    let intersectionSet = new Set();

    for (let x of setA){
        if (setB.has(x)){
            intersectionSet.add(x);
        }
    }

    return intersectionSet;
};
let intersectionAB = intersection(setA, setB);
console.log(intersectionAB);

//alternative - works on FF only
//intersectionAb = new Set([x for (x of setA) if (setB.has(x))]);
//console.log(intersectionAB);

//--------- Difference ----------
let difference = function(setA, setB){
    let differenceSet = new Set();

    for (let x of setA){
        if (!setB.has(x)){
            differenceSet.add(x);
        }
    }

    return differenceSet;
};
let differenceAB = difference(setA, setB);
console.log(differenceAB);

//alternative  - works on FF only
//differenceAB = new Set([x for (x of setA) if (!setB.has(x))]);
//console.log(differenceAB);

你可能感兴趣的:(第6章 集合)