Использование переменной _ (подчеркивание) со стрелочными функциями в ES6 / Typescript


121

Я натолкнулся на эту конструкцию в примере Angular, и мне интересно, почему она выбрана:

_ => console.log('Not using any parameters');

Я понимаю, что переменная _ означает «безразлично» / «не используется», но, поскольку это единственная переменная, есть ли причина предпочесть использование _ вместо:

() => console.log('Not using any parameters');

Конечно, это не может быть примерно на один символ меньше для ввода. На мой взгляд, синтаксис () лучше передает намерение, а также более специфичен для типа, потому что в противном случае я думаю, что первый пример должен был бы выглядеть так:

(_: any) => console.log('Not using any parameters');

Если это важно, это был контекст, в котором он использовался:

submit(query: string): void {
    this.router.navigate(['search'], { queryParams: { query: query } })
      .then(_ => this.search());
}


1
Как вы можете беспокоиться о типе или специфичности типа для параметра, который никогда не используется?

3
Я разработчик C ++ по профессии, поэтому, думаю, меня всегда беспокоит специфичность типов :-).
Остановка

7
Лично шаблон _ => уменьшает количество скобок, что облегчает чтение: doStuff (). Then (() => action ()) vs doStuff (). Then (_ => action ()).
Дэмиен Голдинг

Ответы:


95

Причина, по которой этот стиль можно использовать (и, возможно, почему он был использован здесь), заключается в том, что _он на один символ короче, чем() .

Дополнительные круглые скобки относятся к той же проблеме стиля, что и дополнительные фигурные скобки. . По большей части это вопрос вкуса и стиля кода, но здесь отдается предпочтение многословию из-за согласованности.

В то время как стрелочные функции допускают использование одного параметра без скобок, это несовместимо с нулевым, одним деструктурированным, одним остаточным и несколькими параметрами:

let zeroParamFn = () => { ... };
let oneParamFn = param1 => { ... };
let oneParamDestructuredArrFn = ([param1]) => { ... };
let oneParamDestructuredObjFn = ({ param1 }) => { ... };
let twoParamsFn = (param1, param2) => { ... };
let restParamsFn = (...params) => { ... };

Хотя is declared but never usedошибка была исправлена ​​в TypeScript 2.0 для подчеркнутых параметров, _также может запускатьсяunused variable/parameter предупреждение от линтера или IDE. Это веский аргумент против этого.

_можно условно использовать для игнорируемых параметров (как уже объяснялся другой ответ). Хотя это можно считать приемлемым, такая привычка может привести к конфликту с _пространством имен Underscore / Lodash, а также сбивает с толку, когда есть несколько игнорируемых параметров. По этой причине полезно иметь правильно названные подчеркнутые параметры (поддерживаются в TS 2.0), а также экономит время на выяснение сигнатуры функции и на то, почему параметры помечены как игнорируемые (это противоречит назначению _параметра как ярлыка):

let fn = (param1, _unusedParam2, param3) => { ... };

По причинам, перечисленным выше, я лично считаю _ => { ... }стиль кода плохим тоном, которого следует избегать.


1
Это на один символ короче, но такое же количество нажатий клавиш для большинства IDE, поскольку нажатие (обычно сопровождается расширением ). Я лично предпочитаю использовать pдля параметра, мне также интересно, есть ли у него какие-либо проблемы с производительностью
Mojimi

69

()Синтаксис передает намерения лучше IMHO , а также более типа конкретных

Не совсем. ()говорит, что функция не ожидает никаких аргументов, не объявляет никаких параметров. Функция.length равна 0.

Если вы используете _, он явно указывает, что функции будет передан один аргумент, но вам это не важно. Функция .lengthбудет равна 1, что может иметь значение в некоторых фреймворках.

Так что с точки зрения шрифта это может быть более точный способ (особенно если вы не набираете его, anyа, скажем, _: Event). И, как вы сказали, набирать на один символ меньше, что к тому же легче достать на некоторых клавиатурах.


6
Моя первая мысль заключалась в том, что _ только условно делает очевидным отсутствие аргументов, которые следует учитывать при попытке понять функцию. Использование () делает это явным, нет необходимости сканировать код на предмет возможного использования _ (что нарушит соглашение). Но вы открыли мне глаза, чтобы также рассмотреть ценность документирования того, что в функцию передается значение, которое в противном случае не всегда было бы очевидным.
Остановка

Я только что понял, что мой код полон неиспользуемых _переменных-стрелочных функций, интересно, есть ли разница в производительности по сравнению с использованием()
Mojimi

25

Я думаю, _ =>это просто использовалось, () =>потому что_ это распространено в других языках, где не разрешено просто опускать параметры, как в JS.

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


4
Думаю, Python также следует этому соглашению.
Jaime RGP

7
Это использование _предположительно было заимствовано из функциональных языков, таких как ML и Haskell, где оно задолго до изобретения Python (не говоря уже о Go, Dart или TypeScript).
ruakh

1
также Ruby делает то же самое ( po-ru.com/diary/rubys-magic-underscore ) и F # тоже (и другие языки, находящиеся под влиянием семейства ML)
Мариуш Павельски

Scala любит подчеркивание ( includehelp.com/scala/use-of-underscore-in-scala.aspx ). Какие еще языки последовали за тем, что Scala делает с анонимными типами с подчеркиванием.
Сэм

Я предполагаю, что Scala также заимствовал это из другого языка. В языках программирования едва ли есть что-то, чего не было еще в 70-х: D В основном это просто новые способы комбинировать вещи.
Günter Zöchbauer

11

Можно различать два использования, и некоторые структуры используют это для представления различных типов обратных вызовов. Например, я думаю, что структура node express использует это, чтобы различать типы промежуточного программного обеспечения, например, обработчики ошибок используют три аргумента, а маршрутизация - два.

Такое разграничение может выглядеть как на примере ниже:

const f1 = () => { } // A function taking no arguments
const f2 = _ => { }  // A function with one argument that doesn't use it

function h(ff) { 
  if (ff.length === 0) {
    console.log("No argument function - calling directly");
    ff();
  } else if (ff.length === 1) {
    console.log("Single argument function - calling with 1");
    ff(1);
  }
}

h(f1);
h(f2);


1
Это основано на ответе Берги, но я подумал, что добавление примера - это немного больше редактирования, чем я был бы счастлив сделать с кем-то другим.
Майкл Андерсон,

0

Когда я писал пост, у меня сложилось впечатление, _что это единственный способ создать стрелочные функции без него (), что заставило меня поверить, что использование _может иметь некоторые незначительные преимущества, но я ошибался. @Halt подтвердил в комментариях, что он ведет себя так же, как и другие переменные, это не специальная языковая конструкция.


Я хочу упомянуть еще одну вещь, которую я понял об этих функциях со стрелками подчеркивания, пока тестировал себя, я нигде не упоминал. Вы можете использовать подчеркивание в функции в качестве параметра , хотя это, вероятно, не предназначено для использования, поскольку оно должно представлять неиспользуемый параметр. Для ясности я бы не рекомендовал использовать его таким образом. но может быть полезно знать для таких вещей, как codegolf , задачи, в которых вы пишете самый короткий код (оказывается, вы можете просто использовать любой символ без ()). Я мог бы представить несколько реальных случаев использования, когда библиотеки используют это, и вам нужно использовать его, даже если они не предназначены для этой функции.

Пример:

// simple number doubling function
f = _=> {
    _ = _ * 2;
    return _;
}

console.log(f(2)); // returns 4
console.log(f(10)); // returns 20

Протестировано с помощью консоли Chrome, версия 76.0.3809.132 (официальная сборка) (64-разрядная версия)


1
Подчеркивание «_» - это допустимое имя переменной, а не специальная языковая конструкция, которому по соглашению дано особое значение. Предупреждения ЛИНТЕР о неиспользуемых параметрах можно отключить с помощью префикса подчеркивания. Думаю, _ сам по себе - это кратчайший способ сказать "неиспользованный".
Остановка

@Halt Спасибо за разъяснения, полезно знать наверняка. На самом деле я не понимал, что вы можете создавать стрелочные функции без этого, ()прежде чем я сделал этот пост, я думал, что _это единственный способ, поэтому я решил указать на это. Имея это в виду, оказывается, что в этом нет ничего особенного даже для игры в гольф, поскольку вы можете просто использовать обычного персонажа. Как вы сказали, лучше использовать просто для соблюдения соглашений.
Matsyir
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.