Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Где хранится переменная в замыкании, в случае конструктора? (https://javascript.ru/forum/misc/80506-gde-khranitsya-peremennaya-v-zamykanii-v-sluchae-konstruktora.html)

Launder 14.06.2020 12:08

Где хранится переменная в замыкании, в случае конструктора?
 
Допустим у нас есть код:
function User(fullName)
	{
          var fullArr = fullName.split(' ');  //делаем массив
          
          Object.defineProperty(this, 'firstName',          
          		{
              		       get: function()
                   		    {
                              		 return fullArr[0]; //выдаём первый элемент массива
                                    },
                               set: function(value)
                   		    {
                              		 fullArr[0] = value; // записываем первый элемент массива
                                    }

                        } );
          Object.defineProperty(this, 'lastName',          
          		{
              		       get: function()
                   		    {
                              		 return fullArr[1]; //выдаём второй элемент массива
                                    },
                               set: function(value)
                   		    {
                              		 fullArr[1] = value; //записываем второй элемент массива
                                    }
                         } );
          Object.defineProperty(this, 'fullName',          
          		{
              		       get: function()
                   		    {
                              		 return fullArr[0] + ' ' + fullArr[1]; //выдаём весь массив, через пробел
                                    },
                               set: function(value)
                   		    {
                                         fullArr = value.split(' '); //записываем массив из строки
                                    }
                         } );
	}

var vasya = new User("Василий Тёркин");
var masha = new User("Мария Шарапова");

Итак у нас два разных пользователя. Они, насколько я понимаю, ничем друг другу не мешают. Но мне до конца не понятен механизм их образования: оператор new генерирует создание нового объекта, функция выполняется и выдаёт этот новый объект. Но! Массив fullArr где хранится? если он лежит в функции(конструкторе) User и находится через замыкание, то тогда эти два экземпляра должны мешать друг другу, перезаписывая значения друг друга. Если они не мешают друг другу, значит этот массив каким-то образом принадлежит объекту, но где "там" он лежит?...:-? Спасибо.

MallSerg 14.06.2020 12:36

Очень важно понимать в какой момент и почему происходит замыкание.
Сохранение всего лексического окружения в момент совершения определенного действия при исполнении кода.
Тогда ответ станет очевидным.

Конечно можно дать четкое и понятное разъяснение но это не поможет тебе разобраться в механике работы самой мощной в плане возможностей части JS.

SuperZen 15.06.2020 11:50

function User(fullName) {
  this.fullArr = fullName.split(' ')
}

User.prototype = {
  get firstName() {
    return this.fullArr[0];
  },
  set firstName(value) {
    this.fullArr[0] = value;
  },
}

// или

// Object.defineProperty(User.prototype, 'firstName', {
//   get: function () {
//     return this.fullArr[0];
//   },
//   set: function (value) {
//     this.fullArr[0] = value;
//   },
// })


Вообще код должен был выглядеть примерно так... почему? :)

https://github.com/azat-io/you-dont-...%D0%B8%D 1%8F

https://github.com/azat-io/you-dont-...ect-prototypes

https://github.com/azat-io/you-dont-know-js-ru

Launder 18.06.2020 14:18

Код был приведён специально для того, чтоб задать вопрос по замыканию. В Ваших интерпритациях, SuperZen, никакого замыкания, нет, а значит и вопрос задавать не к чему...

Aetae 18.06.2020 15:17

Мужик, я могу понять таб в четыре пробела, хотя в два - гораздо приятней, но в десять? Зачем?

По вопросу: каждое исполнение функции имеет свой контекст. Каждое создание функции может замыкать переменные из вышестоящего контекста.

При исполнении функции User создаётся контекст, в котором лежит fullArr. При исполнении функции User создаются новые функции-геттеры и функции-сеттеры, которые замыкают на себя вышестоящий контекст.

Launder 18.06.2020 18:57

Aetae
я правильно понимаю, что каждое исполнение функции, создаёт новые переменные и, если результаты этой функции, мы куда-то сохраняем (в какую-то внешнюю, по отношении к функции, переменную), то только эта переменная замыкается на конкретное исполнение функции?
То есть, объект, на который ссылается переменная vasya, и объект, на который ссылается переменная masha, замыкается на конкретное исполнение User, поскольку каждое исполнение независимо и мы о них "помним" только потому, что у каждого из этих объектов, есть ссылка на свою переменную fullArr, сохранившуюся со времён исполнения функции User (при создании конкретного экземпляра объекта)?
При этом, если мы избавимся от конструктора new:
1. уберём new перед переменными.
2. перед геттеро-сеттерами объявим новый объект var object = new Object (или просто = {} ).
3. вместо this в геттерах-сеттерах укажем object.
4. в конце функции вернём return object;

то всё точно также будет работать, поскольку логика замыкания не изменится...
Всё верно или есть ещё какие-то важные, для понимания, детали?
Вы что-то говорили про контекст?...

Aetae 18.06.2020 19:09

Вроде всё верно.
Цитата:

о них "помним" только потому, что у каждого из этих объектов, есть ссылка на свою переменную fullArr, сохранившуюся со времён исполнения функции User
А сохранилась она потому, что во время исполнения были созданы новые функции, которые использовали эту переменную. Иначе GC бы просто очистил от неё память, т.к. на неё не осталось бы ссылок.

Launder 20.06.2020 20:24

Ясненько. Спасибо, теперь, в общем-то ясно...
Получается у нас может быть относительно "простенький" объект, у которого 2,5 поля, а внутри тысячи внутренних переменных сложно регулирующих его поведение...
А можно как-то выяснить, есть ли у объекта какое-то "двойное дно" или, стандартными средствами, это в общем-то, почти нереальная задача?...

Aetae 21.06.2020 07:11

Launder, можно посмотреть в код.)
Ну или на растущую память.

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

Launder 21.06.2020 15:04

Спасибо всем откликнувшимся! Иногда понимаю, что не понимаю, или не достаточно понимаю, каких-то базовых вещей, поэтому придумываю какие-то достаточно простые примеры, чтоб работа какой-то технологии стала очевидной. Большое спасибо за наводки, вроде, в первом приближении, разобрался :)

Launder 25.06.2020 18:33

Скажите а в чём смысл приватных свойств объекта, если их так легко можно реализовать через замыкания?...

voraa 25.06.2020 19:47

Цитата:

Сообщение от Launder
если их так легко можно реализовать через замыкания?...

А как вы в классе опишите замыкание?
class A {
 field1;
 field2;
 constructor () {...}
 meth1 () {...}
 meth2 () {...}
}

Где вы опишите переменную, которую "замыкает"?

Launder 25.06.2020 20:15

Ну отсюда второй вопрос возникает :) В каких ситуациях использования классов, прям уж так необходимо?...
У меня опыт маленький, поэтому, могу чего-то не понимать, но случаев, где я не увидел, как обычные функции полноценно заменяют классы(то есть прекрасно прописывают прототипные ссылки), было, вроде, всего два:
Первое. Когда у нас есть родитель и его метод. И есть наследник, и его метод. И нужно (желательно), чтоб метод наследника назывался также, и содержал в себе уточнённое поведение метода родителя. В этом случае, да, классы удобнее.
Второе. Когда изучал конструктор ошибок. Без классового синтаксиса с его super добиться нормального наследования, не получилось.
Но опять же, я не слишком искушён, возможно, просто плохо себе представлял чего куда прописывать.
А так, иногда создаётся впечатления, что классы, призванные сделать синтаксис более простым и прозрачным, на деле, таковым являются, для решения каких-то достаточно типовых задачах. А настраивать их сложнее... Вот, как раз, в случае с замыканиями. Хочу реализовать приватные свойства, с помощью замыканий они делаются на раз, а без них? Левой ногой через правое ухо :)

Aetae 26.06.2020 07:30

Сейчас добавили для классов настоящие приватные свойства вида:
#<имя>
, раньше просто писали
_<имя>
и соглашались, что мол свойства начинающиеся на
_
считаем приватными и не трогаем снаружи.)

P.S. Лично меня, как адепта монкипатчинга, раздражают эти нововведения. Учитывая среднее качество гонокода в вебе, иметь возможность запатчить что-то внутри - насущная необходимость.)

voraa 26.06.2020 08:54

Цитата:

Сообщение от Aetae
Сейчас добавили для классов настоящие приватные свойства вида:

С поддержкой пока плоховато. Только в хромовых браузерах.
Да и то не полностью. Например, даже в хроме пока нет конструкции o?.#x
Пока нет приватных методов.

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

Launder 26.06.2020 11:47

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

Aetae 26.06.2020 11:55

Модули - это модули, классы - это классы.
Классы нужны для ООП. О преимуществах ООП написаны гигабайты, гуглите.
Модули нужны для удобства разделения кода, не важно ООП вы используете или функциональщину.

voraa 26.06.2020 11:57

Ну как бы одно квадратное, а другое зеленое.

Как модули без использования классов (функций конструкторов) помогут создавать объекты с методами, свойствами, наследованием...?

SuperZen 26.06.2020 11:59

Цитата:

Сообщение от Launder
я не увидел, как обычные функции полноценно заменяют классы

https://ui.dev/javascript-inheritanc...ototype-chain/

Надо вот это прочитать, в этой же книге есть пример из предыдущей ссылки:
https://addyosmani.com/resources/ess...patterns/book/

Introduction
What is a Pattern?
"Pattern"-ity Testing, Proto-Patterns & The Rule Of Three
The Structure Of A Design Pattern
Writing Design Patterns
Anti-Patterns
Categories Of Design Pattern
Summary Table Of Design Pattern Categorization

JavaScript Design Patterns

Constructor Pattern
Module Pattern
Revealing Module Pattern
Singleton Pattern
Observer Pattern
Mediator Pattern
Prototype Pattern
Command Pattern
Facade Pattern
Factory Pattern
Mixin Pattern
Decorator Pattern
Flyweight Pattern

JavaScript MV* Patterns

MVC Pattern
MVP Pattern
MVVM Pattern

Modern Modular JavaScript Design Patterns
AMD
CommonJS
ES Harmony

Design Patterns In jQuery
Composite Pattern
Adapter Pattern
Facade Pattern
Observer Pattern
Iterator Pattern
Lazy Initialization Pattern
Proxy Pattern
Builder Pattern
jQuery Plugin Design Patterns
JavaScript Namespacing Patterns
Conclusions
References

Цитата:

Сообщение от Launder
А так, иногда создаётся впечатления, что классы, призванные сделать синтаксис более простым и прозрачным

это звучит так, что все делается методом тыка... компьютер толи включился, толи выключился, но я жал на кнопки :)...

Цитата:

Сообщение от voraa
o?.#x

o? в хроме работает, но к #x разве можно обращаться (к приватному полю) напрямую (не через публичный метод), или тут что-то другое подразумевалось, тогда, наверное...

voraa 26.06.2020 12:13

Цитата:

Сообщение от SuperZen
o? в хроме работает, но к #x разве можно обращаться (к приватному полю) напрямую (не через публичный метод), или тут что-то другое подразумевалось, тогда, наверное...

Это просто тестовый пример, который определяет поддержку возможности.
class C {
  #x = 42;
  x(o = this){
    return o?.#x;
  }
}
return new C().x() === 42 && new C().x(null) === void 0;

Взят отсюда https://kangax.github.io/compat-table/esnext/

Насколько это реально нужно? Кто его знает
Возможно такая фиговина может понадобится.

SuperZen 26.06.2020 12:41

ну походу еще не готово:
https://github.com/tc39/proposal-opt...ng#open-issues

меньше букав придется писать )

Rise 27.06.2020 13:53

Launder,
Синтаксис модулей и классов был принят в стандарт JS в 2015 году. До этого как-то без них 20 лет жили.

Классы в основном просто более удобный синтаксис для функций-конструкторов - From constructors to classes.
Модули - порождение развития сторонних модульных систем - From CommonJS modules to ES6 modules.

Функции-конструкторы тоже обзывают классами. Не стоит от JS ожидать полноценного класса C++. Приватные свойства приняты в 2019-м. До этого как-то без них 30 лет жили. Бог знает, что нам еще предстоит испытать...

Классы - это свои типы данных. Модули - организация проекта.

Launder 13.07.2020 14:33

Прошу прощения за задержки, разбираюсь наскоками, тестирую возможности модулей. Выразился некорректно - я имел в виду, не синтаксис модулей в ES2015 а паттерн программирования "модуль" (пример, на базе которого экспериментирую взят отсюда,) после заголовка "современные модули". Возможно между ними есть что-то общее (судя, например, по закрытой зоне видимости и инициализации, после которой один и тот же набор переменных, для любого импорта, что-то общее есть), но насколько совпадения полное - не знаю.
А сравниваю с классами вот почему, классы, по сути, не имеют (общих) переменных, а имеют поля, а модули, через замыкания, могут иметь, по-видимому, практически неограниченную сложность внутри, при этом по-умолчанию, доступно только то, что мы сделаем доступным (вероятно, доступным можем сделать всё). Вы пишите "это просто разное", вот и пытаюсь разобраться, что вообще можно делать с помощью модулей и насколько это удобно для возможных изменений/расширений и ввода/вывода. Универсальность подхода, и его "естественные ограничения"...

Rise 13.07.2020 22:29

Цитата:

Сообщение от Launder
после заголовка "современные модули"

Это из серии книг, как там написано, 2013-2015 гг. То что там в "современные модули" описано уже несовременно, а то что в "будущие модули" современно, потому что сейчас 2020-й, а современный JS считается с 2015-го. Есть же местный актуальный Учебник (смотри меню), почему бы не начать с него...

Цитата:

Сообщение от Launder
что вообще можно делать с помощью модулей и насколько это удобно

Модули разделяют код на файлы. которые можно повторно использовать в разных местах. Модули это физическая структура программы, а классы - логическая, вот и всё.

Launder 14.07.2020 15:29

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


Часовой пояс GMT +3, время: 06:38.