Ответ 1
Не существует "стандартного" или "встроенного" способа сделать это. Концептуально, вы просто должны сравнить, что два объекта Map имеют одинаковые ключи и значения для каждого ключа и не имеют дополнительных ключей.
Чтобы сравнение было максимально эффективным, вы можете выполнить следующие оптимизации:
- Сначала проверьте свойство
.size
на обеих картах. Если две карты не имеют одинаковое количество ключей, то вы сразу знаете, они не могут быть идентичными. - Кроме того, гарантируя, что они имеют одинаковое количество ключей, вы можете просто перебрать одну из карт и сравнить ее значения с другой.
- Используйте синтаксис итератора
for (var [key, val] of map1)
для итерации ключей, чтобы вам не приходилось создавать или сортировать массив ключей самостоятельно (это должно быть как быстрее, так и более эффективно использовать память). - Затем, наконец, если вы убедитесь, что сравнение возвращается сразу же, как только обнаружено несоответствие, тогда оно сократит время выполнения, когда они не совпадают.
Затем, поскольку undefined
является допустимым значением в Map, но также и то, что .get()
возвращает, если ключ не найден, мы должны следить за этим, выполняя дополнительный .has()
если сравниваемое значение не undefined
Поскольку и ключи, и значения с объектом Map сами могут быть объектами, это становится намного сложнее, если вы хотите провести глубокое сравнение свойств объектов для определения равенства, а не просто более простой ===
который Javascript использует по умолчанию для проверки того же объекта., Или, если вас интересуют только объекты, у которых есть примитивы для ключей и значений, то этой сложности можно избежать.
Для функции, которая проверяет только строгое равенство значений (проверяет, являются ли они одним и тем же физическим объектом, а не выполняет глубокое сравнение свойств), вы можете сделать то, что показано ниже. При этом используется синтаксис ES6 для эффективной итерации объектов карты и попытки повысить производительность, когда они не совпадают, путем короткого замыкания и возврата false
как только обнаруживается несоответствие.
Для этого фрагмента требуется Firefox 41 или Chrome 49. Он не работает в Edge 25 или IE 11 (возможно, из-за пользователя с типом синтаксиса for/of
ES6, который он использует). Его можно заставить работать в других браузерах, используя более старую технологию для цикла for
, но поскольку в любом случае речь идет о функции ES6 (объект Map), и мы пытаемся оптимизировать реализацию, я решил использовать последнюю версию ES6. синтаксис.
"use strict";
function compareMaps(map1, map2) {
var testVal;
if (map1.size !== map2.size) {
return false;
}
for (var [key, val] of map1) {
testVal = map2.get(key);
// in cases of an undefined value, make sure the key
// actually exists on the object so there are no false positives
if (testVal !== val || (testVal === undefined && !map2.has(key))) {
return false;
}
}
return true;
}
// construct two maps that are initially identical
var o = {"k" : 2}
var m1 = new Map();
m1.set("obj", o);
m1.set("str0", undefined);
m1.set("str1", 1);
m1.set("str2", 2);
m1.set("str3", 3);
var m2 = new Map();
m2.set("str0", undefined);
m2.set("obj", o);
m2.set("str1", 1);
m2.set("str2", 2);
m2.set("str3", 3);
log(compareMaps(m1, m2));
// add an undefined key to m1 and a corresponding other key to m2
// this will pass the .size test and even pass the equality test, but not pass the
// special test for undefined values
m1.set("str-undefined", undefined);
m2.set("str4", 4);
log(compareMaps(m1, m2));
// remove one key from m1 so m2 has an extra key
m1.delete("str-undefined");
log(compareMaps(m1, m2));
// add that same extra key to m1, but give it a different value
m1.set("str4", 5);
log(compareMaps(m1, m2));
function log(args) {
var str = "";
for (var i = 0; i < arguments.length; i++) {
if (typeof arguments[i] === "object") {
str += JSON.stringify(arguments[i]);
} else {
str += arguments[i];
}
}
var div = document.createElement("div");
div.innerHTML = str;
var target = log.id ? document.getElementById(log.id) : document.body;
target.appendChild(div);
}