pseudomap项目是一个ES6之前使用Map数据结构的一个工具库,map的特点在于拓展了对象的键只能是字符串的短板,在ES6之前很容易想到使用一个构造函数来实现,同时对于每一个键值关系使用一个新的对象存储,this.key=key;this.value=value
的形式。适合JavaScript初学者学习构造函数的使用,同时大神的代码质量还是非常值得学习的,大神终究是大神!!!
var hasOwnProperty = Object.prototype.hasOwnProperty
module.exports = PseudoMap
function PseudoMap (set) {
// 检测this的指向来判断该函数是否被当做构造函数运行,使用new实例化
// 构造函数时将改变this的指向为该对象,直接运行函数,this则是指全局对象
if (!(this instanceof PseudoMap)) // whyyyyyyy
throw new TypeError("Constructor PseudoMap requires 'new'")
this.clear()
// 设置传递的参数
if (set) {
if ((set instanceof PseudoMap) ||
(typeof Map === 'function' && set instanceof Map))
set.forEach(function (value, key) {
this.set(key, value)
}, this)
else if (Array.isArray(set))
set.forEach(function (kv) {
this.set(kv[0], kv[1])
}, this)
else
throw new TypeError('invalid argument')
}
}
PseudoMap.prototype.forEach = function (fn, thisp) {
thisp = thisp || this
Object.keys(this._data).forEach(function (k) {
if (k !== 'size')
fn.call(thisp, this._data[k].value, this._data[k].key)
}, this)
}
PseudoMap.prototype.has = function (k) {
return !!find(this._data, k)
}
PseudoMap.prototype.get = function (k) {
var res = find(this._data, k)
// 利用逻辑与的执行特点,不存在时直接返回undefined,这样就不需要在find方法中去判断了,妙
return res && res.value
}
// 存储
PseudoMap.prototype.set = function (k, v) {
set(this._data, k, v)
}
// 删除
PseudoMap.prototype.delete = function (k) {
var res = find(this._data, k)
if (res) {
delete this._data[res._index]
this._data.size--
}
}
PseudoMap.prototype.clear = function () {
// 创建一个空对象
var data = Object.create(null)
data.size = 0
// 重新设置构造函数的_data属性,不可写,不可枚举防止其被篡改
Object.defineProperty(this, '_data', {
value: data,
enumerable: false,
configurable: true,
writable: false
})
}
// 设置size的get方法返回this._data.size
Object.defineProperty(PseudoMap.prototype, 'size', {
get: function () {
return this._data.size
},
set: function (n) {},
enumerable: true,
configurable: true
})
PseudoMap.prototype.values =
PseudoMap.prototype.keys =
PseudoMap.prototype.entries = function () {
throw new Error('iterators are not implemented in this version')
}
// 两者相等或者两个都是NaN时返回true,注意逻辑与的优先级大于逻辑或
// Either identical, or both NaN
function same (a, b) {
return a === b || a !== a && b !== b
}
// 用来储存键值信息的对象
function Entry (k, v, i) {
this.key = k
this.value = v
this._index = i
}
function find (data, k) {
for (var i = 0, s = '_' + k, key = s;
hasOwnProperty.call(data, key);
key = s + i++) {
if (same(data[key].key, k))
return data[key]
}
}
function set (data, k, v) {
// 此时则是重新设置值
for (var i = 0, s = '_' + k, key = s;
hasOwnProperty.call(data, key);
key = s + i++) {
if (same(data[key].key, k)) {
data[key].value = v
return
}
}
// size自增
data.size++
// 将键值关系作为一个Entry对象储存,这样就避免了传统的对象键只能是字符串的短板
data[key] = new Entry(k, v, key)
}
网友评论