Обновить

Комментарии 26

Лень проверять, но всё же: стандартный Map (ECMAScript 2016, но вроде уже давно есть во всех браузерах) проблему не решает?

НЛО прилетело и опубликовало эту надпись здесь
Действительно, отсутствие прототипа помогает. Но нельзя делать вот так, например.
newMap = {...oldMap1, 'newKey': 'newValue' }

Кстати в lodash метод _.groupBy тоже этому подвержен.

Насчет Map — честно говоря, сейчас не помню почему ещё мне не захотелось вызывать методы get и set.
Вспомнил. Cейчас же неделя react vs vue vs angular. В redux есть одно неочевидное требование. Объекты, которые возвращает редюсер должны быть сериализуемы.
Если мы захотим сохранить состояние для последующего восстановления и использования, то в случе Map, после сериализации-десериализации будем иметь не тоже самое, что было до. Это же касается и объекта без прототипа.
Немного подумал, написал вот такой тест. Оказалось, что падает
  it('should return no value for prototype property after serialize/deserialize action', async function (): Promise<void> {
    // arrange
    const map = stringMap();

    // act
    const deserialized = JSON.parse(JSON.stringify(map));
    const ctor = deserialized['constructor'];

    // assert
    expect(noValue(ctor)).to.be.equal(true);
  });

починил, не смог определить, это breaking change или нет. У меня, по крайней мере ничего не сломалось

А для новичков — что за тестовый Фреймворк и где почитать*

Был не прав!
Я использовал в качестве тест-раннера Mocha. И еще chai (assertion library)
У редакса вообще много проблем с (де)сериализацией. Даже не надо такой экзотики как Map, достаточно вспомнить Date. При сериализации он становится строкой и строкой же десериализуется. И есть вполне рабочие методы избежать этого, которые, думается, можно применить и в вашем случае.
Хм, а тупо препендить что-то к ключу, чтобы не натыкаться на зарезервированные слова, это типа костыль и криво выглядит?

Да, я тоже недоумении, мне эта мысль пришла сразу же в голову...

НЛО прилетело и опубликовало эту надпись здесь
Вместо
const a = {};
нужно использовать
const a = Object.create(null);
, если очень хочется реализовать структуру Map
Они, конечно, применимы и даже необходимы, если в качестве ключа нужно использовать объект, а не строку или число.

Не совсем так: ключами объекта могут быть ТОЛЬКО строки. Если использовать число в качестве ключа объекта, оно будет преобразовано в строку.

Ключом объекта может быть Symbol. 2017-ый.
НЛО прилетело и опубликовало эту надпись здесь
ну т.е. смысл статьи в том, что если у вас в ключах могут оказаться «зарезервированные слова» (присутствующие в Object.prototype), то подумайте о том, чтобы не использовать Object?
hasOwnProperty! не?

let b = a.hasOwnProperty(key)? a[key] || 'defaultValue': 'defaultValue';
Или немного покороче:
a.hasOwnProperty(key) && a[key] || 'defaultValue';

Правда читаемость кода…
Если вам, как вы указали выше, важно чтобы Object.Prototype объекта был не null (для redux), то почему бы не написать собственный getter, который бы выглядел как-то так:
function get(object, key){
  return object.hasOwnProperty(key) ? object[key] : undefined
}


Таким образом вы оставите только те свойства объекта, которые принадлежат именно ему, т.е. для вашего map — только добавленные свойства
Меня не прототип null не устраивает, а то что это свойство теряется после некоторых операций. Но честно скажу не знал о возможности создавать объекты без прототипа, может бы и не стал заморачиваться с велосипедостроением.

Геттер с этой проверкой тоже один из вариантов решения, почему нет. Одиночный оверхед во время создания против постоянного оверхеда при работе с объектом.

Afaik, hasOwnProperty — это способ сказать движку, что не надо лезть в прототип и это прекрасно оптимизируется.

Напиши тест (с)
Так есть же Map и WeakMap в ES6
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации