#javascript
Вопрос:
Я читал о классах JavaScript и наткнулся на этот термин «синтаксис полей общедоступных классов«. Копнув немного глубже, я наткнулся на документацию этого Вавилона по свойствам классов.
Может ли кто — нибудь объяснить, пожалуйста, с точки зрения реализации, каковы варианты использования этого нового синтаксиса? (Какие решения/преимущества он предлагает для JavaScript, которых до сих пор не хватало?)
Вот пример ниже (запускался без ошибок в Google Chrome):
class Person {
firstName = "Mike";
lastName = "Patel";
// this is a public class field syntax
getName = () => {
return this.firstName " " this.lastName;
};
}
var p = new Person();
console.log(p.firstName); // Mike
console.log(p.lastName); // Patel
console.log(p.getName); // () => { return this.firstName " " this.lastName; }
console.log(typeof p.getName); // function
console.log(p.getName()); // Mike Patel
Комментарии:
1. Что значит «особенный»? Если вы ожидаете, что это сделает что — то странное и неинтуитивное — тогда нет, это делает именно то, что вы, вероятно, думаете, — это создает два свойства. Это просто новый синтаксис, который сначала был недоступен. В Firefox 68 это выбрасывает
SyntaxError: fields are not currently supported
2. @VLAZ Я проверил в Google Chrome, и он был выполнен без каких-либо ошибок.
3. Это может быть полезно: medium.com/@jacobworrel/…
4. @AadityaSharma опять же, это в Firefox. Это более новый синтаксис, поэтому он не везде реализован полностью. В этом-то и был смысл. Это единственное, что в нем «особенного», но я не знаю, считаете ли вы это «особенным» или нет.
5. @AadityaSharma итак, вместо «что особенного» вы ищете «каков вариант использования». Потому что сам синтаксис не является особенным. Вариант использования заключается в том, почему вы выбрали бы этот, а не другой код.
Ответ №1:
Проще говоря, причина использования этого-простота понимания кода. Без объявлений полей классов вы могли бы сделать что-то вроде:
class Person {
constructor() {
this.firstName = "Mike";
this.lastName = "Patel";
this.getName = () => {
return this.firstName " " this.lastName;
};
}
}
var p = new Person();
console.log(p.firstName); // Mike
console.log(p.lastName); // Patel
console.log(p.getName); // () => { return this.firstName " " this.lastName; }
console.log(typeof p.getName); // function
console.log(p.getName()); // Mike Patel
Это работает, но теперь у вас есть как вызываемые getName()
, так и остальные свойства простого экземпляра, собранные в конструкторе. У вас может быть еще больше, а это означает, что определение вашего класса в целом будет выглядеть довольно бессмысленным:
class MyClass() {
constructor(someArg) {
this.foo1 = 1;
this.foo2 = 2;
this.foo3 = 3;
this.foo4 = someArg;
this.bar1 = () => {}
this.bar2 = () => {}
this.bar3 = () => {}
this.bar4 = () => {}
}
}
и так далее. Опять же, все находится в конструкторе. Если у вас много кода, становится все труднее понять, что есть что. И если конструктор принимает какие-либо аргументы, то у вас есть дополнительные накладные расходы на их отслеживание. Поэтому его трудно читать, трудно поддерживать, и все это без какой-либо реальной пользы. Вы запихиваете все в одно и то же место.
С объявлениями полей классов вы разделяете их и получаете
class MyClass() {
/* properties - do not depend on the constructor*/
foo1 = 1;
foo2 = 2;
foo3 = 3;
foo4; /* this is a property that this class will have -
I do not need to look at the constructor to know about it */
/* easy to see what the constructor does that is only about *constructing* the object */
constructor(someArg) {
this.foo4= someArg;
}
/* callable field are separated from the rest of the simple properties and construction logic */
bar1 = () => {}
bar2 = () => {}
bar3 = () => {}
bar4 = () => {}
}
Таким образом, в целом, это не революционно, но это немного более приятный синтаксис, который облегчает выражение того, что есть у класса.
Комментарии:
1. Поздно для игры в JS с одним вопросом на эту тему, поймите, что предложение поля класса направлено на упрощение метода конструктора. Это то, что нам рекомендуется использовать?
2. @TommyLeong Я бы сказал, что да. Я не вижу реальной пользы в объявлении всего в конструкторе. Эти два метода либо равны, либо поля класса превосходят друг друга.
3. Таким образом, не имеет значения, сможем ли мы использовать это/(другое) предложение, если оно пройдет стадию 4, мы сможем его использовать? Нет никаких проблем в их использовании? Тоже новичок в TC39.
4. @TommyLeong если вы уверены, что среда, в которой вы запускаете свой код, поддерживает поля классов или, по крайней мере, вы используете Babel, то проблем быть не должно.
5. @Bergi очень признателен. Я действительно был небрежен с терминологией, которую использовал. Я перефразировал, чтобы избежать путаницы.
Ответ №2:
Чтобы процитировать предложение по полям классов
Объявляя поля заранее, определения классов становятся более самодокументированными; экземпляры проходят через меньшее количество переходов состояний, так как объявленные поля всегда присутствуют.
Введение полей классов также позволяет создавать частные поля классов, которые также имеют несколько преимуществ:
Определяя вещи, которые не видны за пределами класса, ESnext обеспечивает более надежную инкапсуляцию, гарантируя, что пользователи ваших классов случайно не запутаются в зависимости от внутренних компонентов, которые могут меняться от версии к версии.
Ответ №3:
Оно исходит из этого предложения, в котором рассматривается «проблема».
ПРЕДВАРИТЕЛЬНОЕ ПРЕДЛОЖЕНИЕ
Предположим, что вы хотите иметь класс Foo
, содержащий атрибут по умолчанию, затем вы можете написать по умолчанию следующее
class Foo {
defaultAttribute = 'default';
getDefault() { return this.defaultAttribute; }
}
Помните, что приведенное выше предложение не было реализовано банкоматом. Это defaultAttribute = '...'
игнорируется при настройке объекта класса (при компиляции). Он даже не является частью прототипов или элементов поля (объекта функции).
Это происходит потому defaultAttribute
, что компилятор не улавливает. Поэтому вы не можете этого сделать foo.defaultAttribute
.
Вызов getDefault()
вызовет здесь ошибку, потому что в этот момент она не определена. Эта функция работает, если вы указываете значение defaultAttribute
в конструкторе;
class Foo {
defaultAttribute = 'default';
constructor() {
this.defaultAttribute = 'hello';
}
getDefault() { return this.defaultAttribute; }
}
В этой ситуации значение defaultAttribute
имеет значение «Привет», но оно не переопределило исходную переменную с 'default'
помощью .
ПОСЛЕ ПРЕДЛОЖЕНИЯ
С помощью этого предложения проблема «игнорирования» решается так, что вы можете сделать то, что вы только что описали:
class Foo {
defaultAttribute = 'default';
getDefault() { return this.defaultAttribute; }
}
С помощью этого вы можете пропустить использование constructor()
class Foo1 {
defaultAttribute = 'default';
getDefault() { return this.defaultAttribute; }
}
class Foo2 {
defaultAttribute = 'default';
constructor() {this.defaultAttribute = 'hello';}
getDefault() { return this.defaultAttribute; }
}
const foo1 = new Foo1();
const foo2 = new Foo2();
console.log(foo1.getDefault());
console.log(foo2.getDefault());
Комментарии:
1. »
defaultAttribute = '...'
Игнорируется при настройке объекта класса (при компиляции) » — нет, это не так. Перед реализацией предложения интуитивно напишите, что просто вызовет синтаксическую ошибку. » ВызовgetDefault()
приведет к ошибке здесь, потому что в этот момент она не определена». — нет. Доступ к несуществующим свойствам в JS просто возвращаетundefined
, ошибка не возникает.