ES6新特性:JavaScript中的Map和WeakMap物件

NONO發表於2016-07-27

Map物件

Map物件是一種有對應 鍵/值 對的物件, JS的Object也是 鍵/值 對的物件 ;

ES6中Map相對於Object物件有幾個區別:

1:Object物件有原型, 也就是說他有預設的key值在物件上面, 除非我們使用Object.create(null)建立一個沒有原型的物件;

2:在Object物件中, 只能把String和Symbol作為key值, 但是在Map中,key值可以是任何基本型別(String, Number, Boolean, undefined, NaN….),或者物件(Map, Set, Object, Function , Symbol , null….);

3:通過Map中的size屬性, 可以很方便地獲取到Map長度, 要獲取Object的長度, 你只能用別的方法了;
Map例項物件的key值可以為一個陣列或者一個物件,或者一個函式,比較隨意 ,而且Map物件例項中資料的排序是根據使用者push的順序進行排序的, 而Object例項中key,value的順序就是有些規律了, (他們會先排數字開頭的key值,然後才是字串開頭的key值);

Map例項的屬性

map.size這個屬性和陣列的length是一個意思,表示當前例項的長度;

Map例項的方法

clear()方法, 刪除所有的鍵/值對;
delete(key), 刪除指定的鍵/值對;
entries()返回一個迭代器, 迭代器按照物件的插入順序返回[key, value];
forEach(callback , context) 迴圈執行函式並把鍵/值對作為引數; context為執行函式的上下文this;
get(key) 返回Map物件key相對應的value值;
has(key) 返回布林值, 其實就是返回Map物件是否有指定的key;
keys() 返回一個迭代器,迭代器按照插入的順序返回每一個key元素;
set(key, value) 給Map物件設定key/value 鍵/值對, 返回這個Map物件(相對於Javascript的Set,Set物件新增元素的方法叫做add,而Map物件新增元素的方法為set;
[@@iterator] 和entrieds()方法一樣, 返回一個迭代器, 迭代器按照物件的插入順序返回[key, value];

自己模擬一個Map構造器:

既然知道了Map物件的方法和屬性, 我們也可以自己模擬一個Map構造器, 需要生成器的支援, 所以要在ES5中使用還需要生成器的補丁(模擬Set構造器) :

<html>
<head>
    <meta charMap="utf-8">
</head>
<body>
    <script>
        "use strict";
        class Map {
            /**
             * @param [[key, value], [k, val]];
             * @return void;
             */
            static refresh (arg) {
                for(let [key,value] of arg) {
                    //判斷是否重複了;
                    let index = Map.has.call(this, key);
                    if(index===false) {
                        this._keys.push(key);
                        this._values.push(value);
                    }else{
                        //如果有重複的值,那麼我們執行覆蓋;
                        this._keys[index] = key;
                        this._values[index] = value;
                    }
                };
                this.size = this._keys.length;
            }
            /**
             * @desc return false || Number;
             * */
            static has (key) {
                var index = this._keys.indexOf(key);
                if(index === -1) {
                    return false;
                }else{
                    return index;
                };
            }
            constructor(arg) {
                this._keys = [];
                this._values = [];
                Map.refresh.call(this, arg);
            }
            set (key, value) {
                Map.refresh.call(this, [[key,value]]);
                return this;
            }
            clear () {
                this._keys = [];
                this._values = [];
                return this;
            }
            delete (key) {
                var index = Map.has.call(this, key);
                if(index!==false) {
                    this._keys.splice(index,1);
                    this._values.splice(index,1);
                };
                return this;
            }
            entries () {
                return this[Symbol.iterator]();
            }
            has (key) {
                return Map.has.call(this, key) === false ? false : true;
            }
            *keys() {
                for(let k of this._keys) {
                    yield k;
                }
            }
            *values () {
                for(let v of this._values) {
                    yield v;
                }
            }
            //直接使用陣列的forEach方便啊;
            forEach (fn, context) {
                return this;
            }
            //必須支援生成器的寫法;
            *[Symbol.iterator] (){
                for(var i=0; i<this._keys.length; i++) {
                    yield [this._keys[i], this._values[i]];
                }
            }
        };
        var map  = new Map([["key","value"]]);
        map.set("heeh","dada");
        console.log(map.has("key")); //輸出:true;
        map.delete("key");
        console.log(map.has("key"));  //輸出:false;
        map.set("key","value");
        var keys = map.keys();
        var values = map.values();
        console.log(keys.next());
        console.log(keys.next());
        console.log(values.next());
        console.log(values.next());
        var entries = map.entries();
        console.log(entries);
    </script>
</body>
</html>
Map的使用Demo:
var myMap = new Map();

var keyString = "a string",
    keyObj = {},
    keyFunc = function () {};

// 我們給myMap設定值
myMap.set(keyString, "字串'");
myMap.set(keyObj, "物件");
myMap.set(keyFunc, "函式");

myMap.size; // 輸出長度: 3

// 獲取值
console.log(myMap.get(keyString));    // 輸出:字串
console.log(myMap.get(keyObj));       // 輸出:物件
console.log(myMap.get(keyFunc));      // 輸出:函式

console.log(myMap.get("a string"));   // 輸出:字串

console.log(myMap.get({}));           // 輸出:undefined
console.log(myMap.get(function() {})) // 輸出:undefined

我們也可以把NaN,undefined, 物件,陣列,函式等這些作為一個Map物件的key值 :

"use strict";
let map = new Map();
map.set(undefined, "0");
map.set(NaN, {});
console.log(map); //輸出:Map { undefined => '0', NaN => {} }

迴圈Map的方法

使用Map例項的forEach方法;

"use strict";
let map = new Map();
map.set(undefined, "0");
map.set(NaN, {});
map.forEach(function(value ,key ,map) {
    console.log(key,value, map);
});

使用for…of迴圈:

"use strict";
let map = new Map();
map.set(undefined, "0");
map.set(NaN, {});
for(let [key, value] of map) {
    console.log(key, value);
}
for(let arr of map) {
    console.log(arr);
}

WeakMap

WeakMap是弱引用的Map物件, 如果物件在js執行環境中不存在引用的話,相對應的WeakMap物件內的該物件也會被js執行環境回收;

WeakMap物件的屬性:無

WeakMap物件的方法:

delete(key) : 刪除指定的鍵/值對;

get(key) :返回Map物件key相對應的value值;

has(key) :返回布林值, 其實就是返回Map物件是否有指定的key;

set(key):給Map物件設定key/value 鍵/值對, 返回這個Map物件;

WeakMap相對於Map少了很多的方法, 我們也可以自己再來實現這些方法,比如我們再實現一個Map例項的clear方法:

class ClearableWeakMap {
  constructor(init) {
    this._wm = new WeakMap(init)
  }
  clear() {
    this._wm = new WeakMap()
  }
  delete(k) {
    return this._wm.delete(k)
  }
  get(k) {
    return this._wm.get(k)
  }
  has(k) {
    return this._wm.has(k)
  }
  set(k, v) {
    this._wm.set(k, v)
    return this
  }
}
參考:

MDN:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

ruanyifeng:http://es6.ruanyifeng.com/#docs/set-map

相關文章