Pull to refresh

Comments 26

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

UFO just landed and posted this here
Действительно, отсутствие прототипа помогает. Но нельзя делать вот так, например.
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. При сериализации он становится строкой и строкой же десериализуется. И есть вполне рабочие методы избежать этого, которые, думается, можно применить и в вашем случае.
Хм, а тупо препендить что-то к ключу, чтобы не натыкаться на зарезервированные слова, это типа костыль и криво выглядит?

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

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

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

Ключом объекта может быть Symbol. 2017-ый.
UFO just landed and posted this here
ну т.е. смысл статьи в том, что если у вас в ключах могут оказаться «зарезервированные слова» (присутствующие в 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 — это способ сказать движку, что не надо лезть в прототип и это прекрасно оптимизируется.

Sign up to leave a comment.

Articles