Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pseudomap项目源码阅读 #24

Open
huruji opened this issue Mar 8, 2018 · 0 comments
Open

pseudomap项目源码阅读 #24

huruji opened this issue Mar 8, 2018 · 0 comments

Comments

@huruji
Copy link
Owner

huruji commented Mar 8, 2018

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)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant