pseudomap項(xiàng)目源碼閱讀

pseudomap項(xiàng)目是一個ES6之前使用Map數(shù)據(jù)結(jié)構(gòu)的一個工具庫,map的特點(diǎn)在于拓展了對象的鍵只能是字符串的短板,在ES6之前很容易想到使用一個構(gòu)造函數(shù)來實(shí)現(xiàn),同時(shí)對于每一個鍵值關(guān)系使用一個新的對象存儲,this.key=key;this.value=value的形式。適合JavaScript初學(xué)者學(xué)習(xí)構(gòu)造函數(shù)的使用,同時(shí)大神的代碼質(zhì)量還是非常值得學(xué)習(xí)的,大神終究是大神?。。?/p>

var hasOwnProperty = Object.prototype.hasOwnProperty

module.exports = PseudoMap

function PseudoMap (set) {
    // 檢測this的指向來判斷該函數(shù)是否被當(dāng)做構(gòu)造函數(shù)運(yùn)行,使用new實(shí)例化
    // 構(gòu)造函數(shù)時(shí)將改變this的指向?yàn)樵搶ο螅苯舆\(yùn)行函數(shù),this則是指全局對象
    if (!(this instanceof PseudoMap)) // whyyyyyyy
        throw new TypeError("Constructor PseudoMap requires 'new'")


    this.clear()

    // 設(shè)置傳遞的參數(shù)
    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)
    // 利用邏輯與的執(zhí)行特點(diǎn),不存在時(shí)直接返回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 () {
    // 創(chuàng)建一個空對象
    var data = Object.create(null)
    data.size = 0

    // 重新設(shè)置構(gòu)造函數(shù)的_data屬性,不可寫,不可枚舉防止其被篡改
    Object.defineProperty(this, '_data', {
        value: data,
        enumerable: false,
        configurable: true,
        writable: false
    })
}

// 設(shè)置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時(shí)返回true,注意邏輯與的優(yōu)先級大于邏輯或
// 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) {
    // 此時(shí)則是重新設(shè)置值
    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++
    // 將鍵值關(guān)系作為一個Entry對象儲存,這樣就避免了傳統(tǒng)的對象鍵只能是字符串的短板
    data[key] = new Entry(k, v, key)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容