360SDN.COM

首页/ES6/列表

ES6学习——集合(Collections):WeakMap 应用示例和WeakMap结构

来源:  2018-04-12 10:28:10    评论:0点击:

这里看一下如何利用WeakMap实现class属性的私有化:
 
 
    var Person = (function() {  
        var private = new WeakMap();  
      
        function Person(name) {  
            var privateProperties = {  
                name: name  
            };  
            private.set(this, privateProperties);  
        }  
      
        Person.prototype.getName = function() {  
            return private.get(this).name;  
        };  
      
        return Person;  
    }());  
      
    var p = new Person('John');  
    print('Person 4 name: ' + p.getName());  
    delete p.name;  
    print('Person 4 name: ' + p.getName() + ' — stays private.');  
    print('Person 4 properties: ' + Object.getOwnPropertyNames(p));  
 
 
这样实现起来确实有点复杂,但看起来比较正规。而且这个场合正是weakset发挥作用的场景,因为weakset是弱引用,不会影响垃圾收集。
 
下面还有个例子是模拟java中compareTo的实现,在数组排序的时候可以使用:
 
 
 
    var Person = (function() {  
        var private = new WeakMap();  
    ​  
        function Person(name) {  
            var privateProperties = {  
                name: name  
            };  
            private.set(this, privateProperties);  
        }  
    ​  
        Person.prototype.compareTo = function(other) {  
            var thisName = private.get(this).name;  
            var otherName = private.get(other).name;  
            return thisName.localeCompare(otherName);  
        };  
    ​  
        Person.prototype.toString = function() {  
            return private.get(this).name;  
        };  
    ​  
        return Person;  
    }());  
    ​  
    var people = [  
        new Person('John'),  
        new Person('Jane'),  
        new Person('Jim')  
    ];  
    ​  
    people.sort(function(first, second) {  
        return first.compareTo(second);  
    });  
    ​  
    print('Sorted people: ' + people.join(', '));  
 
 
*以上代码引自:https://curiosity-driven.org/private-properties-in-javascript



 
 
WeakMap的概念在Java中一样存在,和Map的主要区别在于垃圾收集的处理不同。这个数据结构在规范的23.3章节中进行了描述。
 
WeakMap只有key是可GC的,并不是value,这里的概念可能和Java里的不同。
 
 
这里主要说一下和Map区别:
 
1)WeakMap的key必须是object,如果不是就会抛出异常
 
 
 
    var wm = new WeakMap()  
      
    wm.set(1,2)//Uncaught TypeError: Invalid value used as weak map key(…)  
    wm.set({},1)  
 
 
2)WeakMap没有clear方法
 
 
3)WeakMap没有size属性
 
因为它里面的记录可能被GC,无法进行统计。
 
 
4)WeakMap不是可iterable,所以和iterable一系列相关的方法都没有,例如values(),keys()等
 
 
看个简单的例子:
 
 
 
    var m = new WeakMap();  
    var x = { id: 1 },y = { id: 2 };  
    m.set( x, y );  
      
    x = null; // x可以GC了  
    y = null; // y还是不可以GC  
 
 
 
*以上全部代码在Chrome 47下通过测试



WeakMap结构与Map结构基本类似, 唯一的区别是它只接受对象作为键名( null除外), 不接受其他类型的值作为键名, 而且键名所指向的对象, 不计入垃圾回收机制。
 
 
 
    var map = new WeakMap();  
    map.set(1, 2);  
    // TypeError: 1 is not an object!  
    map.set(Symbol(), 2);  
    // TypeError: Invalid value used as weak map key  
 
上面代码中, 如果将1和Symbol作为 WeakMap 的键名, 都会报错。
WeakMap的设计目的在于, 键名是对象的弱引用( 垃圾回收机制不将该引用考虑在内), 所以其所对应的对象可能会被自动回收。 当对象被回收后, WeakMap自动移除对应的键值对。 典型应用是, 一个对应 DOM 元素的WeakMap结构, 当某个 DOM 元素被清除, 其所对应的WeakMap记录就会自动被移除。 基本上, WeakMap的专用场合就是, 它的键所对应的对象, 可能会在将来消失。 WeakMap结构有助于防止内存泄漏。
下面是WeakMap结构的一个例子, 可以看到用法上与Map几乎一样。
 
 
 
    var wm = new WeakMap();  
    var element = document.querySelector(".element");  
    wm.set(element, "Original");  
    wm.get(element) // "Original"  
    element.parentNode.removeChild(element);  
    element = null;  
    wm.get(element) // undefined  
 
上面代码中, 变量wm是一个WeakMap实例, 我们将一个DOM节点element作为键名, 然后销毁这个节点, element对应的键就自动消失了, 再引用这个键名就返回undefined。
WeakMap 与 Map 在 API 上的区别主要是两个, 一是没有遍历操作( 即没有key()、 values() 和entries() 方法), 也没有size属性; 二是无法清空, 即不支持clear方法。 这与WeakMap的键不被计入引用、 被垃圾回收机制忽略有关。 因此, WeakMap只有四个方法可用: get()、 set()、 has()、 delete()。
 
 
 
    var wm = new WeakMap();  
    wm.size  
    // undefined  
    wm.forEach  
    // undefined  
    前文说过, WeakMap 应用的典型场合就是 DOM 节点作为键名。 下面是一个例子。  
    let myElement = document.getElementById('logo');  
    let myWeakmap = new WeakMap();  
    myWeakmap.set(myElement, {  
        timesClicked: 0  
    });  
    myElement.addEventListener('click', function() {  
        let logoData = myWeakmap.get(myElement);  
        logoData.timesClicked++;  
        myWeakmap.set(myElement, logoData);  
    }, false);  
 
上面代码中, myElement是一个 DOM 节点, 每当发生 click 事件, 就更新一下状态。 我们将这个状态作为键值放在 WeakMap 里, 对应的键名就是myElement。 一旦这个 DOM 节点删除, 该状态就会自动消失, 不存在内存泄漏风险。
WeakMap 的另一个用处是部署私有属性。
 
 
 
    let _counter = new WeakMap();  
    let _action = new WeakMap();  
    class Countdown {  
        constructor(counter, action) {  
            _counter.set(this, counter);  
            _action.set(this, action);  
        }  
        dec() {  
            let counter = _counter.get(this);  
            if(counter < 1) return;  
            counter--;  
            _counter.set(this, counter);  
            if(counter === 0) {  
                _action.get(this)();  
            }  
        }  
    }  
    let c = new Countdown(2, () => console.log('DONE'));  
    c.dec()  
    c.dec()  
    // DONE  
 
上面代码中, Countdown 类的两个内部属性_counter和_action, 是实例的弱引用, 所以如果删除实例, 它们也就随之消失, 不会造成内存泄漏。


来源:https://blog.csdn.net/qq_30100043/article/details/53462945

为您推荐

友情链接 |九搜汽车网 |手机ok生活信息网|ok生活信息网|ok微生活
 Powered by www.360SDN.COM   京ICP备11022651号-4 © 2012-2016 版权