Синтаксис Javascript — функция стрелки для класса

#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 />;
    }
  };
}
  

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

  1. оператор export, экспортирующий функцию

  2. функция со стрелкой с одним аргументом и телом, которое является просто оператором return (независимо от того, разделен оператор на строки или нет)

  3. создается анонимный класс

Как вы знаете, функции со стрелкой не нуждаются в круглых скобках, когда у них есть один аргумент, и не нуждаются в фигурных скобках, когда у них есть только оператор 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% анонимными, точно так же, как функции. Свяжите все три вместе, и вам будет сложно проанализировать, что происходит. Я знаю, что мне пришлось взглянуть еще раз.