ES6 Map如何工作

时间:2016-03-09 23:17:39

标签: javascript typescript ecmascript-6

根据我对文档(herehere)的理解,我需要引用内存地址才能使用它:

const foo = {};
const map = new Map();
map.set(foo,'123');  // Can only be done if memory address of `foo` is known. Any other shimming would require stringification of foo

这是因为JavaScript对象{}键只能是字符串(至少在ES5中)。

但我看到Map垫片可用:https://github.com/zloirock/core-js#map。我尝试阅读源代码,但它过于整齐抽象(internally使用strong collection which then imports 10 more files

问题

请回答以下任何一项

  • 是否有一个简单的技巧,甚至可以真正完成(没有字符串化)?
  • 也许它会改变foo以在其上存储一些字符串然后将其用作密钥?
  • 其他东西,也许我正在阅读文档错误?

3 个答案:

答案 0 :(得分:10)

有两种方式可以想到。首先,显然,您可以拥有一系列密钥,并进行线性搜索:



java -jar c:\selenium\selenium-server-standalone-2.21.0.jar -htmlSuite "*firefox" "http://localhost:8080" "c:\test\my-test-suite.html" "c:\test\my-test-result.html"




第二个选项是添加一个特殊的"键"标记到用作关键字的对象:



Map1 = {
    keys: [],
    values: [],
};

Map1.set = function(key, val) {
    var k = this.keys.indexOf(key);
    if(k < 0)
        this.keys[k = this.keys.length] = key;
    this.values[k] = val;
};

Map1.get = function(key) {
    return this.values[this.keys.indexOf(key)];
};


foo = {};
bar = {};

Map1.set(foo, 'xxx');
Map1.set(bar, 'yyy');

document.write(Map1.get(foo) + Map1.get(bar) + "<br>")
&#13;
&#13;
&#13;

与第一个选项不同,第二个选项是O(1)。通过使Map2 = { uid: 0, values: {} }; Map2.set = function(key, val) { key = typeof key === 'object' ? (key.__uid = key.__uid || ++this.uid) : String(key); this.values[key] = val; }; Map2.get = function(key) { key = typeof key === 'object' ? key.__uid : String(key); return this.values[key]; }; foo = {}; bar = {}; Map2.set(foo, 'xxx'); Map2.set(bar, 'yyy'); document.write(Map2.get(foo) + Map2.get(bar) + "<br>")不可写/可枚举,可以更准确地完成它。此外,每个uid应该有自己的&#34; uid&#34; name(可以在Map构造函数中轻松设置)。

答案 1 :(得分:7)

技巧是存储在一个数组中并通过迭代和使用严格比较在O(n)时间内执行查找 - 而不是使用真正的哈希函数,这将是O(1)查找。例如,考虑一下:

var myObj = {};

var someArray = [{}, {}, myObj, {}];

console.log(someArray.indexOf(myObj)); // returns 2

以下是我在另一个答案中的实现:Javascript HashTable use Object key

function Map() {
    var keys = [], values = [];

    return {
        put: function (key, value) {
            var index = keys.indexOf(key);
            if(index == -1) {
                keys.push(key);
                values.push(value);
            }
            else {
                values[index] = value;
            }
        },
        get: function (key) {
            return values[keys.indexOf(key)];
        }
    };
}

答案 2 :(得分:0)

查看我的polyfill here。我不是在宣传我的polyfill,而是我说的是它是我还没有找到的最简单,最直接的,因此它最适合学习和教育分析。基本上,它的工作原理是它使用键的查找表和相应的值表,如下图所示。

var k = {}, j = [], m = document, z = NaN;
var m = new Map([
    [k, "foobar"], [j, -0xf], [m, true], [z, function(){}]
]);




Index      Key                 Value
##### ################    ################
0.    k ({})              "foobar"
1.    j ([])              -15
2.    m (Document)        true
3.    z (NaN)             function(){}

在内部,每个项目都存储在不同的索引中,或者至少这是我喜欢的方式。这也类似于浏览器在内部实现它的方式。不幸的是,我已经看到一些其他的polyfill试图将密钥存储在对象本身上,并且乱用所有内部方法来隐藏它,导致整个网页运行速度慢10000%并且地图速度太快以至于几乎需要只需设置并获取新属性就足够了。另外,我无法理解他们只是试图修补所有内部方法(例如hasOwnProperty)的无数个小时。

至于我的polyfill的工作方式和原因,javascript对象存储在内存中的不同位置。这就是为什么javascript对象数组上的[] !== []和indexOf正常工作的原因。这是因为它们不是同一个数组。