#javascript #reactjs
#javascript #reactjs
Вопрос:
После выполнения некоторых онлайн-руководств я наткнулся на какой-то странный синтаксис JavasSript, с которым я не знаком. В этом руководстве автор делает это
export default ComposedComponent => class extends
Может кто-нибудь объяснить мне, что это значит? Это похоже на функцию жирной стрелки, но, похоже, в ней нет никаких аргументов. он также многострочный, но в нем нет скобок. Что именно это означает?
Ответ №1:
Введение:
Мы «традиционно» объявляем классы ES6 следующим образом:
export default class Apple extends Fruit { ... }
Где Apple
это просто имя класса. В вашем примере:
export default ComposedComponent => class extends Component { ... }
Это просто функция стрелки с аргументом ComposedComponent
и анонимный класс. Это в основном эквивалентно:
export default (ComposedComponent) => {
return class extends Component {
...
}
}
Где class extends Component
— безымянный класс, который расширяет React Component
.
Что это:
Это оболочка компонента более высокого порядка. Вы можете думать об этом как о компоненте React, который оборачивает другой компонент — фабрику компонентов. Он следует синтаксису:
HigherOrderComponentFactory = WrappedComponent: React.Component => NewComponent: React.Component
Где WrappedComponent
— это компонент, который переносится и NewComponent
являющийся новым компонентом более высокого порядка, который возвращается — оба наследуются от React.Component
. Теперь, если вы взглянете на render
метод:
return (
<ComposedComponent
{...this.props}
subscribe={this.subscribe.bind(this)}
subscriptionReady={this.subscriptionReady.bind(this)}
/>
);
Здесь <ComposedComponent {...this.props} />
эквивалентно:
React.createElement(ComposedComponent, this.props, null);
Приложение:
Давайте еще раз взглянем на объявление factory:
export default ComposedComponent => class extends Component { ... }
Функция стрелки (которая сопоставима с упомянутой выше фабрикой) экспортируется по умолчанию и имеет аргумент ComposedComponent
. Здесь ComposedComponent
находится компонент, который будет обернут фабрикой, и class extends Component { ... }
это будет новый компонент более высокого порядка.
В вашем руководстве функция стрелки (или СПЕЦИАЛЬНАЯ фабрика) вызывается следующим образом:
SubscribeComponent(App)
App
другими словами, это компонент, который нужно обернуть ComposedComponent
. Возвращаемый компонент является компонентом более высокого порядка.
Подробнее о компонентах более высокого порядка и их преимуществах можно почитать здесь.
Ответ №2:
Это функция со стрелкой, и у нее действительно есть аргумент ( ComposedComponent
). Он также «многострочный», но это один оператор, следовательно, ему не нужны скобки.
export default ComposedComponent => class extends
Component {
// ...
}
полностью совпадает с
export default ComposedComponent => class extends Component { ... }
И возвращаемый класс является анонимным class X extends Component
.
Редактировать
чтобы расширить комментарии ниже:
В этой единственной строке происходят три вещи, которые могут вызвать путаницу.
export default (ComposedComponent) => {
return class UnnamedClass extends Component {
render () {
return <ComposedComponent />;
}
};
}
написанный таким образом, должно быть легче увидеть, что происходит.
-
оператор export, экспортирующий функцию
-
функция со стрелкой с одним аргументом и телом, которое является просто оператором return (независимо от того, разделен оператор на строки или нет)
-
создается анонимный класс
Как вы знаете, функции со стрелкой не нуждаются в круглых скобках, когда у них есть один аргумент, и не нуждаются в фигурных скобках, когда у них есть только оператор return .
x => x;
Это верно, даже если оператор return занимает несколько строк, в которых не может быть вставки точки с запятой.
() => "1"
"2"
"3";
Где
() => class extends
Component {
// ...
}
входит…
Я бы написал это не так, но это так. Я бы, вероятно, предпочел сделать:
() => class extends Component {
// ...
}
чтобы соответствовать JS, к которому мы все привыкли (хотя декораторы и TS могут это изменить).
Последняя часть важна. Классы, к счастью, анонимны, если вы не помещаете их в положение, в котором им требуется имя.
И если вы подумаете об этом, это имеет полный смысл. На самом деле это просто очищенные версии функций конструктора прошлых лет и не имеют ничего общего с классами в большинстве других языков.
const X = class { constructor () { } };
const x = new X();
ничем не отличается от высказывания
const X = function () { };
const x = new X();
итак
class X {
constructor () { }
}
и
function X () { }
эквивалентны.
Везде, где вы могли бы передать функцию, ожидая, что кто-то new
это сделает, вы могли бы передать анонимный класс.
makeInstance(class {
a () { }
b () { }
});
Свяжите все это вместе, и вы получите
export default ComposedComponent => class extends
Component {
render () {
return (
<ComposedComponent >
// ...
</ComposedComponent>
);
}
}
Комментарии:
1. @AndrewLi это не на месте … Это анонимный класс.
class ___ extends Component
. Вы смотрите на(ComposedComponent) => class UNNAMED_CLASS extends Component { /* ... */ }
2. означает ли это, что ComposedComponent на самом деле является аргументом для UNAMED_CLASS?
3.@LawrenceVo Нет, ты слишком много думаешь об этом.
ComposedComponent
используется только вrender()
методе. В противном случае создаваемый класс является анонимным классом.var anonymous = class extends Component {};
export default class extends Component {}
export default function (ComposedComponent) { return class extends Component { render () { return <ComposedComponent />; } }; }
4. @LawrenceVo Я вижу, что очень легко подумать, что это частный случай синтаксиса ES6. Это не что иное, как три вещи, которые собраны вместе и кажутся сложнее, чем они есть на самом деле. 1) вы объявляете экспорт 2) этот экспорт представляет собой функцию со стрелкой с одним аргументом (
ComposedComponent
) и одним оператором возвратаclass extends Component { }
и, следовательно, не нуждается ни в круглых скобках, ни в фигурных скобках 3) классы могут быть на 100% анонимными, точно так же, как функции. Свяжите все три вместе, и вам будет сложно проанализировать, что происходит. Я знаю, что мне пришлось взглянуть еще раз.