Как узнать, выпущена ли ссылка в JavaScript - PullRequest
2 голосов
/ 20 марта 2019

Я пытаюсь реорганизовать код, который использует let для объявления экземпляра Auth в области действия модуля, который позднее переназначается (в том же модуле) из-за изменения конфигурации. Оригинальная реализация выглядит следующим образом.

let client = new Auth({ config });
// ...later in the same module
export const updateConfig = (_config) => { client = new Auth(_config) };

Мой первый вопрос, это оригинальный Клиент, выпущенный после updateConfig(). Как ты это докажешь? Есть ли недостатки этого подхода?

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

function Client(options) {

  if (Client._instance) {
    return Client._instance;
  }

  if (!(this instanceof Client)) {
    return new Client(options);
  }

  this._instance = new Auth(options);

}

Client.prototype.getInstance = function() { return this._instance };
Client.prototype.updateConfig = function(opts) { 
  this._instance = new Client(opts).getInstance();
}

// usage
const client = new Client({ foo: 'bar'});
client.updateConfig({bar: 'baz'});
console.log(client.getInstance()); // eg. { bar: 'baz' } works!

Применительно к безопасности кода и управлению памятью применяются те же вопросы, какое решение является более подходящим? Это классы аутентификации, поэтому я хочу убедиться, что они собраны правильно и не могут быть использованы неправильно.

Ответы [ 3 ]

3 голосов
/ 20 марта 2019

Мой первый вопрос: оригинальный клиент, выпущенный после updateConfig ()?

Может быть, если client - единственная переменная, которая ссылается на него.

Как ты это докажешь?

Создайте дамп памяти в консоли и выполните поиск этих клиентских объектов.

Есть ли недостатки этого подхода?

Нетдо тех пор, пока никто не ссылается на клиент, которого вы ожидаете обновить:

 const referenced = client;
 updateConfig();
 console.log(referenced === client); // false

Мой предложенный рефакторинг нацелен на то, чтобы сделать это немного менее волшебным ... но, по сути, он делает то же самоевещь

Почему это "менее волшебно", если вы скрываете это изменение за 20 строками кода?Если бы я был рецензентом, я бы отклонил это изменение, потому что оно вводит неожиданное поведение и не дает никакой пользы:

 console.log(new Client === new Client); // true, wtf

Как бы я рефакторинг это (хорошие комментарии недооцениваются):

 // Note: client gets re-set in updateConfig(), do not reference this!
 let client = new Auth({ config });

Какое решение является более подходящим с точки зрения безопасности кода и управления памятью?

«но, по сути, он делает то же самое».Мудрые слова.

1 голос
/ 20 марта 2019

В Javascript GC не является большой проблемой для потенциального злоупотребления информацией, доступной в объектах.Это сами объекты.С современными инструментами разработчика можно легко войти в любую часть кода переднего плана и понять его, если он не запутан.ИМО, в наши дни обфускация в значительной степени необходима.Во-первых, это уменьшает размер файла, а во-вторых, это затрудняет использование кода в производстве.

Теперь перейдем к актуальному вопросу.Как только новый экземпляр new Auth назначен на client, на старый экземпляр более нет жесткой ссылки client, поэтому он может собирать мусор при условии, что другие ссылки не хранятся.Нет гарантии, насколько быстро будет восстановлена ​​память.

И преимуществом использования let является его сфера применения.Это ограничено его блоком.Тем не менее, нередко иметь огромные блоки.По сравнению с глобальными переменными let предлагает вам небольшую область действия и, следовательно, может быть выпущен вскоре после окончания блока.Может также случиться, что среда выполнения Javascript может использовать стек методов для let переменных, и как только блок заканчивается (метод), он удаляет стек и, следовательно, ссылки также удаляются.

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

1 голос
/ 20 марта 2019

Когда мы вызываем new для функции конструктора, она всегда будет возвращать новый объект, что означает, что, когда client был видоизменен позже, теперь он определенно содержит новое значение.Это одно.

Другое дело, что сборщик мусора среды выполнения javascript ищет объекты, которые находятся в памяти, но не являются ссылками ни в одной переменной, и, если они найдены, удаляет их.

Итакв основном, когда я делаю это

let obj = {name: 'Hello'}

obj ссылается на некоторый объект с 2ABCS адресом памяти, а когда я изменяю его

let obj = {name: 'World'}

Теперь он ссылается на объект с адресом 1ABCS что делает 2ABCS сиротой, что означает, что она будет удалена сборщиком мусора

Подробнее читайте https://javascript.info/garbage-collection

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...