Это правильное поведение.
Оператор =
(присваивание) обновляет указатель на новую ячейку памяти, содержащую новое значение, но не изменяет значение, на которое мы в данный момент указываем.
В случае примитивов, таких как строки, общая реализация заключается в том, чтобы фактически скопировать все значение во время повторного назначения переменной.
Дополнительно: обычно это называется Интернирование строк
Вот пример:
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";
var y = x;
x = "456";
Примечание: начальный «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 = {};
var y = x;
x = { name: "foo" };
Когда вы деструктурируете foo
из экземпляра Lib
, это не то же самое foo
, что и внутреннее для этого экземпляра, это новая переменная, указывающая на то же место в памяти, что и внутренняя переменная. Это местоположение содержит {}
.
Когда вы вызываете .configure
, вы обновляете область памяти, на которую указывает внутреннее значение, но неструктурированная переменная все еще указывает на старое местоположение, содержащее {}
.
Если вы обновите объект, на который указывает foo
вместо самой ссылки, все будет работать так, как вы ожидали:
configure({ foo }) {
Object.assign(this.foo, foo);
}
Я бы посоветовал не выполнять деструктуризацию для постоянных получателей, как описано выше, поскольку вы ожидаете, что состояние будет сохраняться при обновлении. Наличие этих дополнительных переменных увеличивает сложность (поскольку увеличивает количество поддерживаемых ссылок) и может также привести к утечкам памяти (устаревшие ссылки указывают на неиспользуемые данные, что предотвращает сбор мусора).
Кроме того, методы деструктуризации вне класса могут привести к ошибкам, подобным приведенным выше, а также к непреднамеренному поведению this
.
Вы избавите себя от нескольких головных болей, если будете всегда звонить Lib.foo
.