ES6 безопасно использовать переменную статического класса в качестве ключа для карты?

В babel-preset-stage-0 мы можем объявить статическую переменную класса следующим образом:

class Constants {
  static COUNTRY = Object.freeze({
      NAME: 'Germany',
      DESCRIPTION: 'placeholder',
  })
}

Безопасно ли использовать Constants.COUNTRY в качестве ключа для ES6 Map или Set?

eg.

const map = new Map();
map.add(Constants.COUNTRY, something);

Гарантируется ли, что map.get(Constants.COUNTRY) всегда будет возвращать something?

Является ли производительность такой же хорошей, как использование строк в качестве ключа? Безопасно ли использовать Constants.COUNTRY как eventKey (атрибут компонента начальной загрузки) и для NavItem?

Также более уместно объявить его как переменную вместо класса? то есть

const Constants = Object.freeze({
  COUNTRY: Object.freeze({
      NAME: 'Germany',
      DESCRIPTION: 'placeholder',
  })
}) 

person Avery235    schedule 21.07.2017    source источник
comment
Ваши данные всегда будут возвращаться только в том случае, если значение Constants.COUNTRY никогда не изменится и никто не удалит этот ключ с карты. Статический класс - это просто переменная, ничем не отличающаяся от вашей альтернативы переменной Constants.   -  person jfriend00    schedule 21.07.2017
comment
Object.freeze предотвращает какое-либо изменение Constants.COUNTRY, но его можно переназначить для переменной статического класса... поэтому я думаю, что последняя версия объявления его как постоянного объекта лучше, чем объявление его как класса.   -  person Avery235    schedule 21.07.2017
comment
Object.freeze() предотвращает изменение объекта (что не имеет значения для карты, поскольку это все тот же объект). Object.freeze() не мешает Constants.COUNTRY = "hello", что имеет значение при доступе к map.get(Constants.COUNTRY).   -  person jfriend00    schedule 21.07.2017
comment
Да, только что заметил это; объявление его как объекта const безопаснее, чем как класс в свете этого...   -  person Avery235    schedule 21.07.2017
comment
Да, ваша вторая форма (с использованием const) предотвратит изменение Constants.Country. Интересно, могли бы вы Object.freeze(Constants) в своем первом примере.   -  person jfriend00    schedule 21.07.2017
comment
@ jfriend00 Только что проверил, Object.freeze(Constants) предотвратит переназначение Constants.COUNTRY, но не переназначение Constants.   -  person Avery235    schedule 21.07.2017
comment
Да, это ожидаемо. Constants нужно будет объявить const, чтобы предотвратить переназначение, как в вашем втором блоке кода (и как описано в моем ответе). Это пункт const, который я полагаю, вы уже знаете.   -  person jfriend00    schedule 21.07.2017


Ответы (2)


Гарантируется ли, что map.get(Constants.COUNTRY) всегда будет что-то возвращать?

Чтобы map.get(Constants.COUNTRY) всегда возвращал исходное значение, должны быть верны несколько вещей.

  1. Вы должны убедиться, что Constants.COUNTRY никогда нельзя будет присвоить другое значение либо потому, что свойство .COUNTRY было переназначено, либо потому, что объект Constants был заменен чем-то другим, имеющим другое значение свойства .COUNTRY.

  2. Вы должны убедиться, что никто никогда не сможет удалить этот ключ из объекта map.

Если вы можете гарантировать эти две вещи, то yes map.get(Constants.COUNTRY) всегда будет возвращать желаемое значение. Но если что-то из этого не обязательно верно, то вы не уверены, что всегда получите свою ценность от карты.

Вы можете гарантировать, что Constants.COUNTRY нельзя изменить, заморозив объект Constants или установив для этого свойства возможность настройки, чтобы его нельзя было удалить или записать в него. Чтобы гарантировать, что объект Constants не может быть заменен, было бы лучше, если бы он был const, как во втором блоке кода.

Я не знаю способа гарантировать, что никто не сможет вызвать map.delete(Constants.COUNTRY), кроме как сохранить объект map закрытым, чтобы посторонний код не мог получить к нему доступ.

Если у вас есть какая-либо причина, по которой вы хотите предотвратить перечисление ключей на карте (возможно, чтобы кому-то было труднее обнаружить ключ), вы можете использовать WeakMap вместо Map.

Является ли производительность такой же хорошей, как использование строк в качестве ключа?

Вам нужно будет протестировать конкретную реализацию Javascript, чтобы быть уверенным в производительности. Нет обязательной причины реализации, по которой тот или иной должен быть быстрее - это просто будет зависеть от внутренних компонентов реализации.

Я создал тестовый пример jsPerf для сравнения поиска строк. для поиска объектов. Приветствуются отзывы об улучшении того, как это тестируется/измеряется, но, используя текущую схему, в которой я создаю 10 000 строковых ключей и 10 000 ключей объектов на карте, а затем сравниваю доступ к 1000 каждого из них, я получаю разные результаты.

Chrome is ~20% slower to access the object keys.
Firefox is ~20% slower to access the string keys.
Edge is ~27% slower to access the string keys.

Также более уместно объявить его как переменную вместо класса?

Как уже говорилось, ваша вторая форма const имеет то преимущество, что Constants нельзя переназначить.

person jfriend00    schedule 21.07.2017
comment
Добавлены данные измерения производительности строковых ключей по сравнению с ключами объектов. - person jfriend00; 21.07.2017
comment
Только что обнаружил недостаток объявления его как const (связанный с подъемом, если я не ошибаюсь): я не могу добавить новую переменную/функцию в Constants, которая ссылается на Constants.COUNTRY, поэтому мне придется объявить COUNTRY перед Constants затем добавьте его в Constants, который не такой СУХОЙ. Я думаю, тогда класс был бы лучше... любой, кто решит импортировать класс и переназначить его, не должен писать коды. - person Avery235; 21.07.2017
comment
@ Avery235 - const Constants означает только то, что Constants нельзя переназначить. Это не имеет ничего общего с назначением свойств объекту Constants. Вы заблокированы от этого из-за вашего Object.freeze(). Вы можете заморозить объект после того, как закончите его создание. - person jfriend00; 21.07.2017
comment
class Constant { static a = 1; static b = Constant.a } работает, но не const Constant = { a: 1, b: Constant.a }. Мне нужно сделать const a = 1; const Constant = { a: a, b: a }. - person Avery235; 21.07.2017
comment
При объявлении const Constant = {...} вы не можете ссылаться на Constant внутри статического объявления (поскольку оно еще не существует внутри объявления). Но вы можете объявить const Constant = {...}, а затем в следующих строках после этого объявления добавить еще несколько свойств, таких как Constant.a = Constant.foo. И затем, после добавления всех необходимых свойств, вы можете Object.freeze(Constant). - person jfriend00; 21.07.2017
comment
class Constant { static a = 1; static b = Constant.a; static c = Constant.b } приятнее читать, чем Constant.a = 1; Constant.b = Constant.a; Constant.c = Constant.b, сохраняет все в блоке класса. Хотя вопрос довольно тривиальный... - person Avery235; 21.07.2017

Вы можете использовать от WeakMap до COUNTRY в качестве ключа и something в качестве значения. Переменная, объявленная с помощью const, не может быть удалена. Наряду с использованием Object.freeze(), wm.get(COUNTRY) всегда должно возвращать something

  const wm = new WeakMap;

  const COUNTRY = Object.freeze({
    NAME: 'Germany',
    DESCRIPTION: 'placeholder',
  });

  wm.set(COUNTRY, "something");

  // error when "use strict"
  delete wm;
  delete COUNTRY;

  COUNTRY.NAME = 123;

  console.log(
    wm.get(COUNTRY)
  );
  
  console.log(
    COUNTRY
  );
  
  console.log(
    wm
  );


Если требуется переменная, которую нельзя удалить или изменить, вы можете использовать const, см. Можно ли удалить переменную, объявленную с помощью const? и JSON

"use strict";

// `Constants` cannot be changed or deleted
const Constants = `{
  "NAME": "Germany",
  "DESCRIPTION": "placeholder"
}`;

console.log(
  JSON.parse(Constants)
);

// delete Constants;
/*
Error: {
  "message": "Uncaught SyntaxError: Delete of an unqualified identifier in strict mode."
}
*/

person guest271314    schedule 21.07.2017
comment
В чем преимущество слабой карты перед обычной картой в этом случае? - person jfriend00; 21.07.2017
comment
@ jfriend00 Невозможность перечислить ключ, если это можно назвать преимуществом; зависит от того, чего OP в конечном итоге пытается достичь с помощью шаблона в первую очередь. Также OP может использовать const вместо class, хотя эта часть ответа не должна влиять на использование WeakMap или Map. OP упомянул производительность, сборку мусора. - person guest271314; 21.07.2017
comment
Куда было поставлено требование или даже желание не иметь возможности перечислить ключ из map? - person jfriend00; 21.07.2017
comment
@jfriend00 Есть ли преимущество в тексте ответа? - person guest271314; 21.07.2017
comment
Вы предлагаете ответ, в котором используется WeakMap. Я не понимаю, почему это интересный ответ или почему WeakMap более полезен для ответа на вопрос, чем Map, который уже использует ОП. Я просто нахожу это запутанным ответом, который не объясняет сам себя. И wm.delete(COUNTRY) сделает так, что wm.get(COUNTRY) больше не будет возвращать ничего полезного, поэтому ваше последнее предложение верно только с этим квалификатором (уже упомянутым в моих комментариях, но не в вашем ответе). - person jfriend00; 21.07.2017
comment
@ jfriend00 OP спрашивает о производительности. Также более уместно объявить ее как переменную, а не класс? По сути, Вопрос представляет собой не жизнеспособную постановку проблемы, а скорее, с точки зрения здесь, как использовать объект в качестве ключа, возможно, закрытого ключа. const можно использовать вместо class. WeakMap удерживается слабо, может собираться мусором там, где больше нет ссылок. Это то, что просматривается при прочтении Вопроса. Если, с вашей точки зрения, кода в Вопросе достаточно для запроса, опубликуйте ответ на этот вопрос. - person guest271314; 21.07.2017
comment
@ jfriend00 Ваше предположение, что ответ бесполезен? - person guest271314; 21.07.2017
comment
@jfriend00 Если невозможно удалить или изменить переменную, OP может заменить const на Map, WeakMap или class. - person guest271314; 21.07.2017