Комментарии 32
Вывод от меня: когда вкручивали async/await, как обычно, не нашлось знающего JS человека, чтобы подсказать горе-стандартизаторам, что функции могут вызываться и через `new`, и неплохо бы предусмотреть асинхронность и в этом месте.
Если я не ошибаюсь, то асинхронных конструкторов нет и в других языках. По крайней мере поиск не дал результатов на язык C#.
await же просто ждёт резолва промиса. Возвращайте из конструктора промис, будет у вас асинхронный конструктор.
var A = class {
constructor(foo) {
this._foo = foo;
return new Promise((resolve) => {
setTimeout(() => {
resolve(this);
}, 1000);
})
}
getFoo() {
return this._foo;
}
};
(async () => {
var a = await new A(5);
console.log(a.getFoo());
})();
А как все-таки связаны приватные и асинхронные конструкторы?
Если я где-то упоминал про асинхронные конструкторы, то процитируйте, пожалуйста, а-то, вроде, всю статью перечитал - не нашёл :D
Под "асинхронным созданием экземпляра класса" я имел ввиду, что может случится примерно следующий кейс:
class Payment {
constructor(props) {
this.#props = props;
}
#props;
static async fromServer(link) {
const data = await fetch(link).then(res => res.json());
return new Payment(data);
}
}
Я думал привести подобный пример, но чувство, что меня за это архитекторы ПО в подворотне испинают :D
Ага, значит тут мы получаем данные платежа с сервера и создаём на их основе объект.
А что если мы получили данные платежа из другого источника? Прочитали из файла? Забили константами, потому что у нас модульный тест? В чём проблема обратиться к конструктору когда у нас есть данные платежа?
Приведу вам пример из жизни. Вот есть у вас Uint8Array с данными криптографического ключа. Вам нужно создать экземпляр обёртки:
const key = new Key( data )
И.. это не компилируется, так как функция импорта ключа - асинхронная. И приходится менять конструктор на фабрику:
const key = await Key.from( data )
Функция импорта ключа возвращает CryptoKey. И, скорее всего, именно этот CryptoKey и будет передан в конструктор.
Внимание, вопрос: есть ли какая-то действительно важная причина запрещать прямой вызов конструктора, если у вызывающей стороны уже каким-то чудом есть корректный CryptoKey?
Она принимает 100500 параметров. Собственно для того обёртка и нужна, чтобы не возиться с этими функциями напрямую. И подобное костылеварение ещё долго продолжаться будет, пока все методы высшего порядка и операторы не будут продублированы в асинхронном варианте.
И что дальше? Я всё ещё не понимаю как из 100500 параметров некоторой функции следует необходимость сделать конструктор класса приватным.
ВСЁ это — синтаксический сахар. Ничего нового, просто удобства.
Слишком сложно.
Основная проблема приватного конструктора — в том, что класс и его конструктор в js — это одно и то же, и нельзя выставить наружу первое не выставив второго.
Однако, зачем в принципе может понадобиться скрывать конструктор? Рассмотрим всё тот же класс Fahrenheit. Если вызвать его конструктор, то случится … что? Мы успешно преобразуем "фаренгейты" в "фаренгейты"? Звучит как совершенно корректная операция.
С асинхронными "конструкторами" та же самая история. Я ещё не видел ситуаций, когда бы действительно необходимо было скрывать конструктор.
Однако, если скрыть конструктор всё же нужно — почему бы не скрыть весь класс?
class Fahrenheit {
constructor(value) {
this.#value = value;
}
#value;
}
Fahrenheit.prototype.constructor = null;
export function fromCelsius(value) {
return new Fahrenheit(value * 9/5 + 32);
}
class Fahrenheit {
constructor(value, key) {
if (Fahrenheit.#key !== key) throw new Error("Using of raw constroctor is not allowed. Use fromCelsius method instead.");
this.#value = value;
}
static #key = new Object();
#value;
static fromCelsius(value) {
return new Fahrenheit(value * 9/5 + 32, Fahrenheit.#key);
}
}
А вообще, пример, конечно, притянут за уши. Обычно, приватные конструкторы нужны для реализации синглтонов. Но в JS можно реализовать синглтон и без этого.
class Singleton {
constructor(val) {
if (Singleton.#instance != null) return Singleton.#instance;
Singleton.#instance = this;
this.Val = val;
}
Val;
static #instance;
}
По вкусу, можно добавить выбрасывание ошибки при повторном явном вызове конструктора, статический метод getInstance, ну и т.д.
На вскидку, сложно сказать, насколько реально нужен приватный конструктор в JS, но он уж точно не является приоритетом. Вот чего не хватает, так это модификатора protected. Уж если начали модификаторы доступа добавлять, не стоило останавливаться на private.
Испытал диссонас. JS сообщество идёт по пути функционального программирования, а новый стандарт дал угла в сторону ООП или я чего-то не понимаю?! Разъясните для новичка пожалуйста.
Во-первых, когда стандарт принимали, так сильно сообщество в сторону ФП ещё не шло.
Во-вторых, что плохого в мультипарадигменности языка программирования?
В-третьих, куча функций — ещё не ФП, и сообщество зашло на путь ФП не так далеко как многие думают.
Это только плюс, когда есть такие возможности. Я с этим солидарен. Однако бытует мнение, что на классах писать не солидно. Особенно это касается React-a. Тип, мол так сообщество не пишет. Хотя моё видение на этот счёт, что надо использовать все возможности языка. Пусть даже код будет чуть длиннее, но зато более читаемый. (речь о классах).
Много читал про это. По этому просто выражу свою благодарность за ваш ответ.
По поводу классовых компонентов. У них есть одна проблема, которая описана в этой статье. Сейчас проверил - она до сих пор актуальна.
Не уверен что это именно проблема. Отслеживать устаревающие данные нужно в любом случае, и функциональные компоненты хорошо справляются лишь в простейших случаях. Подробности — в комментариях по вашей же ссылке.
Проблема классовых компонентов только одна - они хуже декомпозируются и имеют склонность превращаться в год-обжекты того или иного размера, с довольно низким cohesion. Да и реактовская центральная идея "ui как значение от стейта" более естественно вписывается в функции.
Но, как уже говорил, это относится только к компонентам. Писать логику может быть удобнее в духе ООП (хотя тут субъективно).
Потрясающе. Выдавать проблему работы с устаревшим состоянием за достоинство - это надо уметь.
Приватные конструкторы JavaScript