Значение разрушенной переменной не сохраняется между модулями - PullRequest
0 голосов
/ 29 октября 2018

Я получаю противоречивые результаты при передаче объектов между модулями в приложении Node JS или, возможно, просто неправильно понимаю, что происходит!

В моем приложении, записанном в псевдокоде ниже, сначала в корень приложения требуется файл lib, а затем другие службы, используемые приложением, которые также требуются в той же библиотеке. Затем библиотека настраивается в корне приложения - это устанавливает переменную класса (this.foo), которая была инициализирована как пустой объект в библиотеке, - и, наконец, вызывается метод в одной из служб.

Свойство foo деструктурировано в верхней части служебного файла, и если я сразу же выхожу из него, я получаю пустой объект (как и ожидалось). Когда я вызываю метод service, после того, как foo был сконфигурирован в другом месте, и ссылаюсь на свойство destructured, я все равно получаю пустой объект. Если вместо этого я не деструктурирую свойство и просто требую в библиотеке (Lib), то в методе, к которому я обращаюсь к Lib.foo, я вижу настроенное значение (то есть, как и ожидалось).

Я подозреваю, что деструктурированная переменная является значением, которое не обновляется, а необходимая библиотека является ссылкой, но все, что я прочитал, говорит о том, что по значению ничего не передается. Любые указатели будут оценены!

// main.js
// ========
const lib = require('./lib');
const service = require('./service');
lib.configure({ foo: "bar"});
service.run();


// service.js
// ========
const Lib = require('./lib');     // This is for the example only
const { foo } = require('./lib'); // I'd prefer to just do this

console.log(Lib.foo); // {} as expected
console.log(foo);     // {} as expected

class Service {
    run() {
        console.log(foo);    // {} - should be "bar"
        console.log(Lib.foo) // "bar" as expected
    }
}
module.exports = new Service();


// lib.js
// ======
class Lib {
    constructor() {
        this.foo = {}
    }
    configure({ foo }) {
        this.foo = foo;
    }
}
module.exports = new Lib();

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

Так что я думаю, что вы путаете ссылки и ценности. Причина, по которой значение {foo} не изменяется, в то время как значение Lib.foo изменяется, заключается в том, что в случае foo вы назначаете копию значения Lib.foo в то время, Если вы хотите изменить данные Lib и распространить их, вам нужно будет работать с объектом (а не деконструировать аргумент, который вы делаете сейчас).

Надеюсь, это поможет!

0 голосов
/ 29 октября 2018

Это правильное поведение.

Оператор = (присваивание) обновляет указатель на новую ячейку памяти, содержащую новое значение, но не изменяет значение, на которое мы в данный момент указываем.

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

Дополнительно: обычно это называется Интернирование строк

Вот пример:

var x = "123";  // point the variable named "x" to a memory location containing the string "123"
var y = x;      // point the variable named "y" to a new memory location into which we copy the data from the memory location that "x" is pointing to
x = "456";      // point the variable named "x" to a new memory location that that contains the value "456"
console.log(y); // still "123", "y" still points to a memory location containing the copy of "123"

А вот диаграмма того, что происходит.

var x = "123";

case 1

var y = x;

case 2

x = "456";

case 2

Примечание: начальный «123» все еще остается в памяти, за исключением того, что ничто больше не указывает на него, поэтому сборщик мусора со временем его очистит.

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

var x = {};          // point the variable named "x" to a memory location containing the empty object
var y = x;           // point the variable named "y" to the same memory location that "x" is pointing to
x = { name: "foo" }; // point the variable named "x" to a new memory location that contains the object { name: "foo" }
console.log(y);      // still {}, "y" still points to a memory location containing the empty object

Вот диаграмма того, что происходит:

var x = {};   

case 1

var y = x;

case 2

x = { name: "foo" };

case 3

Когда вы деструктурируете foo из экземпляра Lib, это не то же самое foo, что и внутреннее для этого экземпляра, это новая переменная, указывающая на то же место в памяти, что и внутренняя переменная. Это местоположение содержит {}.

Когда вы вызываете .configure, вы обновляете область памяти, на которую указывает внутреннее значение, но неструктурированная переменная все еще указывает на старое местоположение, содержащее {}.

Если вы обновите объект, на который указывает foo вместо самой ссылки, все будет работать так, как вы ожидали:

configure({ foo }) {
    Object.assign(this.foo, foo);
}

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

Кроме того, методы деструктуризации вне класса могут привести к ошибкам, подобным приведенным выше, а также к непреднамеренному поведению this.

Вы избавите себя от нескольких головных болей, если будете всегда звонить Lib.foo.

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