Map
对象保存键值对,并且能够记住键的原始插入顺序。任何值可以作为一个键或一个值
实现
先写好骨架
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| var MyMap = (function(){ var symbolNaN = Symbol('NaN') function _encode(val){ return val !== val ? symbolNaN : val } function _decode(val){ return val === symbolNaN ? NaN : val } function _forOf(obj, cb){ if(typeof obj[Symbol.iterator] !== 'function') throw new TypeError('Symbol.iterator is not a function') if(typeof cb !== 'function') throw new TypeError('cb is not a function') var iteratee = obj[Symbol.iterator]() var res while(true){ res = iteratee.next() if(res.done) break cb(res.value) } } function _createIterator(list, iterator){ var next = 0 var obj = { next: function(){ return next < list.length ? { done: false, value: iterator(list[next++]) } : { done: true, value: undefined } }, } obj[Symbol.iterator] = function(){ return obj } return obj } function _Map(values){} _Map.prototype.has = function(key){} _Map.prototype.set = function(key, val){} _Map.prototype.get = function(key){} _Map.prototype.delete = function(key){} _Map.prototype.clear = function(){} _Map.prototype.keys = function(){} _Map.prototype.values = function(){} _Map.prototype.entries = function(){} _Map.prototype.forEach = function(fn, context){} return _Map })();
|
构造函数
接受一组可迭代器对象,使用双数组分别存储 key
和 value
,一一映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
function _Map(values){ var self = this this._key = [] this._value = [] Object.defineProperty(self, 'size', { enumerable: false, configurable: false, get(){ return self._key.length } }) _forOf(values, function(val){ if(typeof val !== 'object') throw new TypeError('value must be an object') self.set(val[0], val[1]) }) }
|
has
map
中是否存在指定元素
1 2 3 4 5 6 7 8
|
_Map.prototype.has = function(key){ return this._key.indexOf(_encode(key)) !== -1 }
|
set
为 map
添加记录
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
_Map.prototype.set = function(key, val){ key = _encode(key) var i = this._key.indexOf(key) if(i === -1) i = this.size this._key[i] = key this._value[i] = val return this }
|
get
获取 map
中的某个元素
1 2 3 4 5 6 7 8 9 10 11
|
_Map.prototype.get = function(key){ key = _encode(key) var i = this._key.indexOf(key) if(i === -1) return undefined return this._value[i] }
|
delete
移除 map
中的元素
1 2 3 4 5 6 7 8 9 10 11 12 13
|
_Map.prototype.delete = function(key){ key = _encode(key) var i = this._key.indexOf(key) if(i === -1) return false this._key.splice(i, 1) this._value.splice(i, 1) return true }
|
clear
清除 map
中所有元素
1 2 3 4 5 6 7
|
_Map.prototype.clear = function(){ this._key = [] this._value = [] }
|
keys & values & entries & forEach
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
_Map.prototype.keys = function(){ return _createIterator(this._key, function(key){ return _decode(key) }) }
_Map.prototype.values = function(){ return _createIterator(this._value, function(value){ return value }) }
_Map.prototype.entries = function(){ var res = [] var len = this._key.length var i = 0 while(i < len){ res[i] = [_decode(this._key[i]), this._value[i++]] } return _createIterator(res, function(entry){ return entry }) }
_Map.prototype.forEach = function(fn, context){ var i = 0 var len = this._key.length while(i < len){ fn.call(context, _decode(this._key[i]), this._value[i++], this) } }
|
补上迭代器补丁,完成
1 2 3 4
| _Map.prototype[Symbol.iterator] = function(){ return this.entries() } return _Map
|
测试一波
1 2 3 4 5 6 7 8 9 10 11 12
| const m1 = new MyMap([[1,2]]) console.log(m1.has(1)) console.log(m1.set(1, 3)) console.log(m1.set(NaN, 4)) console.log(m1.get(NaN)) console.log(m1.set(NaN, 5)) console.log(m1.get(NaN)) console.log([...m1.keys()]) console.log([...m1.values()]) console.log([...m1.entries()]) console.log([...m1]) m1.forEach(console.log)
|

源码地址