对打字稿地图的迭代失败 [英] iteration over a typescript map failing

查看:102
本文介绍了对打字稿地图的迭代失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用下面的函数比较两张地图。有趣的是for循环中的代码永远不会被执行。因此, console.log(key,val)代码永远不会执行。当然,我确保我正在比较的地图不是空的,并且大小相同,以强制执行for循环中的代码。我犯了一个非常愚蠢的错误或错过了一个深刻的概念吗?

  private compareMaps(map1,map2){
var testVal;
if(!(map1&& map2)){
return false;
}
if(map1.size!== map2.size){
return false;
}
for(var [key,val] map1){
testVal = map2.get(key);
console.log(key,val);
if(testVal!== val ||(testVal === undefined&&!map2.has(key))){
return false;
}
}
返回true;
}


解决方案


有趣的是for循环中的代码永远不会被执行。我犯了一个非常愚蠢的错误或错过了一个深刻的概念吗?


你错过了......



for ... of 在TypeScript中的 Map 上不起作用在ES6之前



当它在ES6之前定位ECMAScript时,TypeScript编译器为语句的...转换进入 for 循环。



此代码:

  for(var [key,val]地图){
console.log(key);
}

成为此代码:



($ _ $ = 0,map_1 = map; _i< map_1.length; _i ++){
var _a = map_1 [_i],key = _a [0 ],val = _a [1];
console.log(key);
}

怎么办?



选项1 :当我们必须在ES6之前定位ECMAScript时, forEach 函数可以替代 for ... of 循环。请注意, forEach 对于的有微妙的差异(例如,提前退出,async / await)。

  map.forEach((val,key)=> {
console.log(key +:+ val);
});

选项2 :当我们必须在ES6之前定位ECMAScript时,我们必须具有的确切行为 John Weisz的答案有意义:将 Map 转换为数组并迭代数组



选项3 :当我们可以定位 ECMAScript ES6或更高版本时,请使用 for ... of 直接在地图上循环。



旁白:地图平等



如果要求是地图平等,请考虑 每个函数。这需要在迭代中 break 的需要,因为每个在找到第一个<$ c时立即返回$ c> false



如果订单比较重要,请使用像这样:

  function areEqual< K,V>(map1:Map< K,V>, map2:Map< K,V>){
if(!map1 ||!map2)返回false;
const array1 = Array.from(map1.entries());
const array2 = Array.from(map2.entries());
返回array1.every(([k1,v1],index)=> {
const [k2,v2] = array2 [index];
返回k1 === k2& & v1 === v2;
});
}

如果订单无关紧要,那么我们想要集平等;使用每个,如下所示:

  function areSetEqual< K,V>( map1:Map< K,V>,map2:Map< K,V>){
if(!map1 ||!map2)返回false;
const array1 = Array.from(map1.entries());
const array2 = Array.from(map2.entries());
返回array1.length === array2.length&&
array1.every(([k1,v1])=> map2.get(k1)=== v1);
}

以下是有效功能的演示:

  const map1 = new Map([[key1,val1],[key2,val2]]); 
const map2 = new Map([[key1,val1],[key2,val2]]);
const map3 = new Map([[key2,val2],[key1,val1]]);

console.log(areEqual(map1,map2)); // true
console.log(areEqual(map1,map3)); // false
console.log(areSetEqual(map1,map2)); // true
console.log(areSetEqual(map1,map3)); // true


I'm using the function below to compare two maps. What's interesting is that the code inside for loop is never executed. So, console.log(key,val) code is never executed. Of course I made sure that the maps I'm comparing are not empty and are of same size to force execution of the code inside the for loop. Am I making a really silly mistake or am missing a deep concept?

private compareMaps(map1, map2) {
        var testVal;
        if (!(map1 && map2)) {
            return false;
        }
        if (map1.size !== map2.size) {
            return false;
        }
        for (var [key, val] of map1) {
            testVal = map2.get(key);
            console.log(key, val);
            if (testVal !== val || (testVal === undefined && !map2.has(key))) {
                return false;
            }
        }
        return true;
    }

解决方案

What's interesting is that the code inside for loop is never executed. Am I making a really silly mistake or am missing a deep concept?

You're missing the fact that...

for...of does not work on Map in TypeScript prior to ES6

When it targets ECMAScript prior to ES6, the TypeScript compiler transpiles the for...of statement into a for loop.

This code:

for (var [key, val] of map) {
    console.log(key);
}

Becomes this code:

for (var _i = 0, map_1 = map; _i < map_1.length; _i++) {
    var _a = map_1[_i], key = _a[0], val = _a[1];
    console.log(key);
}

What to do?

Option 1: When we must target ECMAScript prior to ES6, the forEach function can be a suitable alternative to the for...of loop. Beware though that forEach has subtle differences from for...of (e.g. exiting early, async/await).

map.forEach((val, key) => { 
    console.log(key + ":" + val);
});

Option 2: When we must target ECMAScript prior to ES6, and we must have the exact behavior of for...of, the answer by John Weisz makes sense: convert the Map to an Array and iterate the Array with for...of.

Option 3: When we can target ECMAScript ES6 or later, use the for...of loop directly on the Map.

Aside: Map Equality

If the requirement is Map equality, consider the every function. That takes care of the need to break in the iteration, because every immediately returns when it finds the first false.

If order matters to the comparison, use every like this:

function areEqual<K,V>(map1: Map<K,V>, map2: Map<K,V>) { 
    if(!map1 || !map2) return false;
    const array1 = Array.from(map1.entries());
    const array2 = Array.from(map2.entries());
    return array1.every(([k1, v1], index) => {
        const [k2, v2] = array2[index];
        return k1 === k2 && v1 === v2;
    });
}

If order does not matter, then we want set equality; use every like this:

function areSetEqual<K, V>(map1: Map<K, V>, map2: Map<K, V>) { 
    if(!map1 || !map2) return false;
    const array1 = Array.from(map1.entries());
    const array2 = Array.from(map2.entries());
    return array1.length === array2.length &&
        array1.every(([k1, v1]) => map2.get(k1) === v1);
}

Here is a demo of the functions in action:

const map1 = new Map([["key1", "val1"], ["key2", "val2"]]);
const map2 = new Map([["key1", "val1"], ["key2", "val2"]]);
const map3 = new Map([["key2", "val2"], ["key1", "val1"]]);

console.log(areEqual(map1, map2)); // true
console.log(areEqual(map1, map3)); // false
console.log(areSetEqual(map1, map2)); // true
console.log(areSetEqual(map1, map3)); // true

这篇关于对打字稿地图的迭代失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆