摘要:然而,對象字面量不是真正意義上的哈希映射,如果使用不當(dāng)可能會構(gòu)成潛在的隱患??諏ο髣?chuàng)建一個真正的哈希映射的秘訣就是避免原型,及其帶來的包袱。在此之前,甚至之后,你應(yīng)該使用空對象滿足你所有的基本哈希映射需求。
對象字面量存在的問題在JavaScript中存儲鍵值對的一個簡單常見的方法是使用對象字面量。然而,對象字面量不是真正意義上的哈希映射,如果使用不當(dāng)可能會構(gòu)成潛在的隱患。雖然目前JavaScript可能沒有提供原生的hashmap(至少不能跨瀏覽器),對象字面量如果沒有隱患就能達(dá)到所需的功能也許是一個更好的選擇。
對象字面的問題在于其原型鏈繼承自Object原型上的對象和方法會破壞其維持鍵值的機(jī)制。以toString方法為例,使用in操作符檢查同名屬性會導(dǎo)致錯誤的結(jié)果:
javascriptvar map = {}; `toString` in map; // true
上面的錯誤之所以會發(fā)生,是因?yàn)?b>in操作符會從對象的原型鏈上查找繼承屬性。為了解決該問題,我們可以用hasOwnProperty方法來確定鍵值的存在性,因?yàn)樵摲椒ㄖ粰z查對象本身的屬性:
javascriptvar map = {}; map.hasOwnProperty("toString"); // false
上面的方法能夠良好的工作,除非你遇到一個名為hasOwnProperty鍵。重寫此方法將會因?yàn)閲L試調(diào)用hasOwnProperty方法而導(dǎo)致意外的行為,根據(jù)新的值最有可能導(dǎo)致錯誤:
javascriptvar map = {}; map.hasOwnProperty = "foo"; map.hasOwnProperty("hasOwnProperty"); // TypeError
一個快速的修正方法是利用一個通用且沒有被篡改的對象字面量,并在你指定的hashmap上下文中執(zhí)行hasOwnProperty方法:
javascriptvar map = {}; map.hasOwnProperty = "foo"; {}.hasOwnProperty.call(map, "hasOwnProperty"); // true
盡管實(shí)際工作時(shí)沒有任何問題,但對象字面量還是限制了它的使用。舉個例子,每次你在for...in循環(huán)里面遍歷一個對象的屬性,你都要過濾其原型鏈中的屬性:
javascriptvar map = {}; var has = {}.hasOwnProperty; for (var key in map) { if(has.call(map, key)) { // ... } }
一段時(shí)間后,可能會變得有點(diǎn)乏味。值得慶幸的是,有一個更好的辦法。
空對象創(chuàng)建一個真正的哈希映射的秘訣就是避免原型,及其帶來的包袱。我們可以利用ES5中引入的Object.create方法達(dá)到該目的。該方法的特別之處在于你可以給一個新對象明確定義原型。舉個例子,用一個較復(fù)雜的方式定義一個簡單對象字面量:
javascriptvar obj = {}; // 等價(jià)于 var obj = Object.create(Object.prototype);
除了能夠定義一個你選擇的原型,你也能夠通過傳入一個null放棄傳入原型:
javascriptvar map = Object.create(null); map instanceof Object; // false Object.prototype.isPrototypeOf(map); // false Object.getPrototypeOf(map); // null
這些空對象對于哈希映射是理想的,因?yàn)槿鄙?b>[[Prototype]]避免了命名沖突。由于該對象完全是空的,它會抵制任何形式的強(qiáng)制轉(zhuǎn)換,試圖這樣做將導(dǎo)致一個錯誤:
javascriptvar map = Object.create(null); map + ""; // TypeError: Cannot convert object to primitive value
空對象沒有任何初始值或者字符串表現(xiàn)形式,因?yàn)榭諏ο蟪俗鳛殒I值對的存儲空間沒有為任何其他事情做打算,簡單又普通。
注意hasOwnProperty方法在空對象中也消失了,這無關(guān)緊要,因?yàn)?b>in操作符可以無異常的工作了:
javascriptvar map = Object.create(null); "toString" in map; // false
更好的是,乏味的for...in循環(huán)變得更加簡單。我們最終可以按其本身的意思寫一個循環(huán):
javascriptvar map = Object.create(null); for (var key in map) { // ... }
雖然存在差異,但對所有的意圖和目的,它仍然表現(xiàn)得就像一個對象字面量。屬性可以利用.或則[]訪問,對象可以被序列化,且對象仍然可以使用上下文對象的原型方法:
javascriptvar map = Object.create(null); Object.defineProperties(map, { "foo": { value: 1, enumerable: true }, "bar": { value: 2, enumerable: false } }); map.foo; // 1 map["bar"]; // 2 JSON.stringify(map); // {"foo": 1} {}.hasOwnProperty.call(map, "foo"); // true {}.propertyIsEnumerable.call(map, "bar"); // false
甚至不同檢查類型的方法將會告訴你從對象字面中期望得到什么:
javascriptvar map = Object.create(null); typeof map; // object {}.toString.call(map); // [object Object] {}.valueOf.call(map); // Object {}
這一切使得空對象代替對象字面量變得簡單,讓他們很好地集成到一個現(xiàn)有的應(yīng)用程序,而不會引起大范圍的變化。
總結(jié)在簡單的鍵值存儲的背景下,使用空對象是對象字面量的有效替代方案,用明確的定義消除對象字面量的怪癖。對于更全面的數(shù)據(jù)結(jié)構(gòu),ES6將以Map和Set形式引入原生的hashmap。在此之前,甚至之后,你應(yīng)該使用空對象滿足你所有的基本哈希映射需求。
歡迎光臨我的個人博客:風(fēng)影博客
參考原文地址:True Hash Maps in JavaScript
Object.create()
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/92325.html
摘要:為了防止你錯過了之前的文章,以下是鏈接第一部分給開發(fā)者的源碼源碼結(jié)構(gòu)第二部分理解內(nèi)部函數(shù)的定義第三部分的變量實(shí)現(xiàn)所有的東西都是哈希表基本上,里面的所有東西都是哈希表。哈希后的結(jié)果可以被作為正常的數(shù)組的鍵值又名為內(nèi)存塊。表示哈希表的容量。 文章來自:http://www.hoohack.me/2016/02/15/understanding-phps-internal-array-im...
摘要:正文在年,框架的選擇并不少。特別的,通過思考這些框架分別如何處理狀態(tài)變化是很有用的。本文探索以下的數(shù)據(jù)綁定,的臟檢查的虛擬以及它與不可變數(shù)據(jù)結(jié)構(gòu)之間的聯(lián)系。當(dāng)狀態(tài)產(chǎn)生變化時(shí),只有真正需要更新的部分才會發(fā)生改變。 譯者言 近幾年可謂是 JavaScript 的大爆炸紀(jì)元,各種框架類庫層出不窮,它們給前端帶來一個又一個的新思想。從以前我們用的 jQuery 直接操作 DOM,到 Backb...
摘要:原文譯者插件能夠?qū)⒁娴娜繚摿Ρ┞督o第三方的開發(fā)者。當(dāng)將一個插件應(yīng)用到環(huán)境中,這個插件將會獲得一個對于這個的引用。表示有關(guān)模塊資源,已編譯資源,已更改文件和監(jiān)視依賴關(guān)系的當(dāng)前狀態(tài)的信息。 原文:how to write a plugin 譯者:neal1991 welcome to star my articles-translator , providing you advanc...
摘要:使用能優(yōu)雅的構(gòu)建并且與單頁面應(yīng)用程序完美結(jié)合。我們將重點(diǎn)關(guān)注所需的所有部分,然后在后續(xù)教程中,我們將進(jìn)一步演示如何使用作為層。例如,如果用戶刷新路由,我們將需要匹配該路由并返回應(yīng)用程序模板。運(yùn)行應(yīng)用程序該基礎(chǔ)用于構(gòu)建具有和路由器的。 使用Laravel能優(yōu)雅的構(gòu)建API并且與Vue單頁面應(yīng)用程序(SPA)完美結(jié)合。在本教程中,我們將展示如何啟動和運(yùn)行Vue路由器以及用于構(gòu)建SPA的La...
摘要:原文引言這篇文檔包含了如何避免使代碼性能遠(yuǎn)低于預(yù)期的建議尤其是一些會導(dǎo)致牽涉到等無法優(yōu)化相關(guān)函數(shù)的問題一些背景在中并沒有解釋器但卻有兩個不同的編譯器通用編譯器和優(yōu)化編譯器這意味著你的代碼總是會被編譯為機(jī)器碼后直接運(yùn)行這樣一定很快咯并不是 原文:http://dev.zm1v1.com/2015/08/19/javascript-optimization-killers/引言 這篇文檔包...
閱讀 1648·2023-04-25 20:36
閱讀 2070·2021-09-02 15:11
閱讀 1209·2021-08-27 13:13
閱讀 2662·2019-08-30 15:52
閱讀 4714·2019-08-29 17:13
閱讀 1011·2019-08-29 11:09
閱讀 1499·2019-08-26 11:51
閱讀 847·2019-08-26 10:56