#javascript #typescript #ecmascript_6
Помогите пожалуйста отрефакторить код. Я написал компонент, который представляет из себя форму для отправки вопросов. Так же он выводит заданные на настоящий момент вопросы (пока в консоль, но это не принципиально). Вместо базы данных для учебных целей использую localstorage. Итак, вот мой сервис, которые работает с "базой данных": @Injectable() export class QuestionsService { private questions: Question[]; constructor() { this.questions = localStorage.questions ? JSON.parse(localStorage.questions) : []; } getQuestions() { console.log('qqq'); return this.questions; }; setQuestions(question): void { this.questions.push(question); localStorage.questions = JSON.stringify(this.questions); }; } Вот описанный тип: export class Question { text: string; speakerId: number; dateHuman: string; dateUnix: string; } Вот компонент: export class QuestionComponent implements OnInit { private questions: Question[] = []; constructor(private questionsService: QuestionsService) { } ngOnInit() { this.getQuestions(); console.log(this.questions); } private sendQuestion(): void { this.questionsService.setQuestions({ "text": "42256yregd", "speakerId": 23, "dateHuman": "223 oct", "dateUnix": "22222" }); }; private getQuestions(): void { this.questionsService.getQuestions().map(question => { this.questions.push(question); }); }; } Эта система работает. Но мне хотелось бы использовать новые модные геттеры и сеттеры из стандарта es6. Вот моя попытка: Сервис: private questions: Question[]; constructor() { this.questions = localStorage.questions ? JSON.parse(localStorage.questions) : []; } get questions() { console.log('qqq'); return this.questions; }; set questions(question): void { this.questions.push(question); localStorage.questions = JSON.stringify(this.questions); }; компонент: .... .. private sendQuestion(): void { this.questionsService.questions = { "text": "42256yregd", "speakerId": 23, "dateHuman": "223 oct", "dateUnix": "22222" }; }; private getQuestions(): void { this.questionsService.questions().map(question => { this.questions.push(question); }); }; .... .... Но консоль выводит ошибку: Duplicate identifier 'questions'.
Ответы
Ответ 1
Проблема у вас вот в чем: private questions: Question[]; // раз get questions() { // два set questions(question): void { У вас объявлено два свойства с одним именем. Так нельзя делать, о чем вам и говорит tsc. Эта проблема решается добавлением префикса к приватному свойству: private _questions: Question[]; get questions() { set questions(question): void {Ответ 2
Здесь get questions() { ... return this.questions; }; вы через замыкание рекурсивно вызываете геттер questions. До возвращения значения дело не доходит, потому как превышается максимальный стек рекурсивного вызова функции. Интерпретатор понимает запись this.questions не как "обратись к свойству questions объекта this", а как "получи значение свойства questions объекта this". А получение значения происходит при помощи обращения к геттеру, который в данном случае имеет то же имя, что и само свойство questions, что и приводит к неверному результату (к "бесконечной" рекурсии). В конечном итоге вам выдается предупреждение об этом. Но. Так было бы, если бы интерпретатор самостоятельно не пресекал подобное поведение. На самом деле до рекурсивного вызова дело даже не доходит, поскольку интерпретатор (компилятор) сразу обнаруживает, что у вас в коде коллизия имен - имя свойства совпадает с именем геттера. В случае с сеттером, обращаясь внутри него к this.questions вы, опять же, обращаетесь не напрямую к свойству questions, а, из-за наличия геттера, сначала именно к нему [к геттеру]. Соответственно, по логике, и переопределяете вы тоже не свойство, а геттер. Но, повторюсь, судя по ошибке, которую вы получили, подобное поведение все-таки как-то чем-то перехватывается. В ином случае мы бы, возможно, довольно долго гадали, в чем же дело. Ну или просто получили бы ошибку вроде описанной выше. Решение проблемы В любом случае, ваша проблема решается путем разграничения имени свойства и его accessor'ов (геттеров и сеттеров). В идеальном случае стоит делать само свойство приватным, а геттер и сеттер - публичными. Но, поскольку ограничения доступа, как такового, EcmaScript не предусматривает (даже его 6-ая версия), то придется полагаться на добропорядочность тех, кто использует ваш код. А именно, дать свойству имя _questions, а getter'у и setter'у - просто questions. Таким образом вы убиваете сразу двух зайцев: избавляетесь от нежелательного поведения и явно указываете, что само свойство является приватным (ну или защищенным). Обращу ваше внимание, что, по-факту, вы можете использовать любое имя, а вариант с нижним подчеркиванием я привел в качестве наиболее правильно (по ряду причин, описанных выше). Исходя из всего сказанного, ваши геттер и сеттер должны выглядеть как-то так (соответственно): get questions() { console.log('qqq'); return this._questions; // добавлено нижнее подчеркивание }; set questions(question): void { this._questions.push(question); localStorage.questions = JSON.stringify(this.questions); };
Комментариев нет:
Отправить комментарий