Правильное использование const для определения функций в JavaScript

183

Мне интересно, есть ли какие-либо ограничения на то, какие типы значений могут быть установлены с помощью constJavaScript - в частности, функции. Это действительно? Конечно, это работает, но считается ли это плохой практикой по какой-либо причине?

const doSomething = () => {
   ...
}

Должны ли все функции быть определены таким образом в ES6? Не похоже, что это завоевало популярность, если так.

Спасибо за любые комментарии!

Дэвид Синклер
источник
Вы, кажется, задаете несколько вопросов: 1) «Мне интересно, есть ли какие-либо ограничения на то, какие типы значений могут быть установлены с помощью const в JavaScript» № 2) «Это допустимо?» Да. 3) «считается ли это плохой практикой по какой-либо причине», я думаю, это не было достаточно долго, чтобы что-то сказать об этом, но я не понимаю, почему это должна быть практика пэдов. Это не сильно отличается от var doSomething = <function def>;. 4) «Должны ли все функции быть определены таким образом в ES6?» Мне кажется обременительным. Мне нравятся объявления функций. Каждому свое.
Феликс Клинг
1
То, как я это вижу (мнение, а не факт), имеет смысл, если вы хотите запретить переопределение функций. Будь то в здравом уме, или имеет ли он какой - то функциональное назначение - это спорный вопрос. Если вы считаете, что это соответствует вашему сценарию использования, я не думаю, что кто-то может оспорить ваше решение и посчитать это плохой практикой.
Mjh
4
Я думаю, вопрос в том, чего ты хочешь достичь const. Вы хотите предотвратить переопределение функции? Я предполагаю, что вы знаете свой код, чтобы не делать этого в любом случае. Вы хотите выразить намерение doSomething, то есть, что оно содержит функцию и не меняет ее значение? Я думаю, что объявления функций также ясно выражают эту цель. Итак, если вам нужна «защита во время выполнения» от переопределения, сделайте это. В противном случае я не вижу большой пользы. Конечно, если бы вы прежде использовали var foo = function() {};, я бы использовал constвместо var.
Феликс Клинг
5
@FelixKling: «Я предполагаю, что вы знаете свой код, чтобы не делать этого в любом случае». - это довольно плохой аргумент. Иначе смысла нет constвообще.
Меандр

Ответы:

254

Нет проблем с тем, что вы сделали, но вы должны помнить разницу между объявлениями функций и выражениями функций.

Объявление функции, то есть:

function doSomething () {}

Поднимается полностью до верхней части прицела (и тому подобное, letи constони также имеют объемную область).

Это означает, что будет работать следующее:

doSomething() // works!
function doSomething() {}

Функциональное выражение, то есть:

[const | let | var] = function () {} (or () =>

Это создание анонимной функции ( function () {}) и создание переменной, а затем присвоение этой анонимной функции этой переменной.

Таким образом, обычные правила, связанные с подъемом переменных в области видимости - переменные в области блока ( letи const) не поднимаются undefinedдо вершины их области видимости блока.

Это означает:

if (true) {
    doSomething() // will fail
    const doSomething = function () {}
}

Сбой, так doSomethingкак не определено. (Это бросит ReferenceError)

Если вы переключитесь на использование, varвы получите подъем переменной, но она будет инициализирована undefinedтак, что приведенный выше блок кода все равно не будет работать. (Это вызовет, TypeErrorпоскольку doSomethingне является функцией во время вызова)

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

Аксель Раушмайер (Axel Rauschmayer) имеет большой пост о сфере применения и подъеме, включая семантику es6: переменные и область видимости в ES6

tkone
источник
7
Хотелось бы добавить, что классы es6 внутренне используют const для защиты имени класса от переназначения внутри класса.
user2342460
2
Одно тонкое различие между a function a(){console.log(this);} и b const a=_=>{console.log(this);} состоит в том, что если вы назовете его так a.call(someVar);, как в a , он напечатает someVar, в b , он напечатает window.
Цянь Чен
100

Хотя использование constдля определения функций кажется хаком, но оно дает некоторые большие преимущества, которые делают его превосходным (на мой взгляд)

  1. Это делает функцию неизменной, поэтому вам не нужно беспокоиться об изменении этой функции каким-либо другим фрагментом кода.

  2. Вы можете использовать синтаксис жирной стрелки, который короче и чище.

  3. Использование функций стрелок позаботится о thisсвязывании для вас.

пример с function

// define a function
function add(x, y) { return x + y; }

// use it
console.log(add(1, 2)); // 3

// oops, someone mutated your function
add = function (x, y) { return x - y; };

// now this is not what you expected
console.log(add(1, 2)); // -1

тот же пример с const

// define a function (wow! that is 8 chars shorter)
const add = (x, y) => x + y;

// use it
console.log(add(1, 2)); // 3

// someone tries to mutate the function
add = (x, y) => x - y; // Uncaught TypeError: Assignment to constant variable.
// the intruder fails and your function remains unchanged

GAFI
источник
1
И вы можете дважды объявить функцию add (x, y), но вы не можете объявить дважды const add = ...
TatianaP
33
1. Неизменность является реальным преимуществом, но очень редко кто-то действительно перезаписывает функцию. 2. Синтаксис жирной стрелки не короче, если ваша функция не может быть выражением. function f(x, y) {18 символов, const f = (x, y) => {21 символ, поэтому на 3 символа больше. 3. Сохранение этой привязки имеет значение, только если функции определены внутри метода (или другой функции, которая имеет значение this). На верхнем уровне сценария это бессмысленно. Я не говорю, что вы не правы, просто причины, о которых вы упомянули, не очень актуальны.
Nakedible
@Nakedible так, каковы другие веские причины?
Аниш Рамасвами
13
Одно из преимуществ старомодного синтаксиса функции заключается в том, что во время отладки оно имеет имя.
user949300
3
Я бы использовал линтеры для предотвращения повторного связывания объявления функции.
Франклин Ю
32

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

Q: Мне интересно, есть ли какие-либо ограничения на то, какие типы значений могут быть установлены с помощью const в JavaScript - в частности, функции. Это действительно? Конечно, это работает, но считается ли это плохой практикой по какой-либо причине?

Я был мотивирован, чтобы провести некоторое исследование после наблюдения одного плодовитого кодировщика JavaScript, который всегда использует constоператор for functions, даже когда нет явной причины / выгоды.

В ответ на вопрос « считается ли это плохой практикой по какой-либо причине? », Позвольте мне сказать, ИМО, да, или, по крайней мере, есть преимущества в использовании functionутверждений.

Мне кажется, что это во многом вопрос предпочтений и стиля. Есть несколько хороших аргументов, представленных выше, но ни один из них не настолько ясен, как это делается в этой статье:

Постоянная путаница: почему я все еще использую операторы JavaScript, написанные medium.freecodecamp.org/Bill Sourour, гуру JavaScript, консультантом и учителем.

Я призываю всех прочитать эту статью, даже если вы уже приняли решение.

Вот основные моменты:

Операторы функций имеют два явных преимущества перед выражениями функций [const]:

Преимущество № 1: Ясность намерений

При сканировании тысяч строк кода в день полезно иметь возможность выяснить намерения программиста как можно быстрее и проще.

Преимущество № 2: Порядок декларации == Порядок исполнения

В идеале я хочу объявить мой код более или менее в том порядке, в котором, как я ожидаю, он будет выполнен.

Для меня это showtopper: любое значение, объявленное с использованием ключевого слова const, недоступно до тех пор, пока его не достигнет выполнение.

То, что я только что описал выше, заставляет нас писать код, который выглядит с ног на голову. Мы должны начать с функции самого низкого уровня и двигаться вверх.

Мой мозг не работает таким образом. Я хочу контекст перед деталями.

Большая часть кода написана людьми. Поэтому имеет смысл, что порядок понимания большинства людей примерно соответствует порядку выполнения большинства кода.

JMichaelTX
источник
1
Можете ли вы прокомментировать немного больше ясности намерений? Я получаю # 2, но, насколько я могу судить, # 1 - это просто (до?) Повторение # 2. Я могу вспомнить случай, то есть функции, имеющие свои собственные defaultErrorHandlerconst, назначенные как анонимные функции, которые я затем могу вызывать из обработчиков обещаний. Это позволило бы мне по желанию «переопределить» этот обработчик ошибок по умолчанию внутри функций, как мне было нужно. Некоторым просто нужно вернуть объект ошибки, а другим - HTTP-ответ, с разной степенью детализации. Тем не менее, структура кода может быть знакомой моделью независимо.
Джейк Т.
Может быть, моя идея слишком запутанная, хотя! Я просто обернул голову вокруг некоторых новых практик, пока не потратил кучу времени на их реализацию. Просто обнаружение, что мне действительно нравится .then( res.success, res.error )намного больше, чем анонимные функции, которые я объявил, просто вызывает res.success(value);. Имея .then( ..., defaultErrorHandler)общий шаблон может быть приятно, с уровнем верхнего определенной функцией defaultErrorHandler, и необязательно иметь const defaultErrorHandler = error => { ... }объявлено в пределах области видимости функции по желанию.
Джейк Т.
1
@JakeT. RE «Можете ли вы прокомментировать немного больше ясности намерений?». Ну, во-первых, это заявление было сделано не мной, а автором этой статьи freecodecamp.org/Bill Sourour. Но это имеет смысл для меня. Если я читаю «функция завтра ()», я сразу же узнаю, что это функция. Но если я читаю «const завтра = () =>», я на мгновение останавливаюсь и анализирую синтаксис в своей голове, чтобы окончательно определить, ОК, да, это функция.
JMichaelTX
1
Другое дело, если у меня есть длинный скрипт, написанный кем-то другим, и я хочу увидеть все функции, я могу быстро выполнить поиск по «функции», чтобы найти их. Или, что еще лучше, я могу написать быстрый JS RegEx для извлечения всех функций. IMO, выражение "const" предназначено только для данных (не функций), которые НЕ изменятся.
JMichaelTX
10

Есть некоторые очень важные преимущества в использовании, constи некоторые сказали бы, что его следует использовать везде, где это возможно, из-за того, насколько оно преднамеренное и показательное.

Насколько я могу судить, это наиболее показательное и предсказуемое объявление переменных в JavaScript и одно из самых полезных, ПОСКОЛЬКУ от того, насколько оно ограничено. Зачем? Потому что это исключает некоторые возможности varи letобъявления.

Что вы можете сделать, когда читаете const? Вы знаете все следующее, просто прочитав constоператор объявления И не просмотрев другие ссылки на эту переменную:

  • значение привязано к этой переменной (хотя ее базовый объект не является глубоко неизменным)
  • к нему нельзя получить доступ вне его немедленно содержащего блока
  • привязка никогда не доступна до объявления из-за правил временной мертвой зоны (TDZ).

Следующая цитата взята из статьи, в которой говорится о преимуществах letи const. Он также более прямо отвечает на ваш вопрос об ограничениях / ограничениях ключевого слова:

Ограничения, подобные тем, которые предлагаются letи constявляются мощным способом облегчения понимания кода. Постарайтесь накапливать как можно больше таких ограничений в написанном вами коде. Чем больше декларативных ограничений ограничивают то, что может означать фрагмент кода, тем проще и быстрее людям читать, анализировать и понимать фрагмент кода в будущем.

Конечно, есть больше правил для constобъявления, чем для varобъявления: блок-область, TDZ, назначение при объявлении, без переназначения. Принимая во внимание, что varзаявления только сигнализируют функцию определения объема. Однако подсчет правил не дает большого понимания. Лучше взвесить эти правила с точки зрения сложности: правило добавляет или уменьшает сложность? В случае const, когда область видимости блока означает более узкую область видимости, чем область видимости функции, TDZ означает, что нам не нужно сканировать область назад от объявления, чтобы определить использование перед объявлением, а правила присваивания означают, что привязка всегда будет сохранять та же ссылка.

Чем более ограничены операторы, тем проще становится фрагмент кода. Поскольку мы добавляем ограничения к тому, что может означать оператор, код становится менее непредсказуемым. Это одна из главных причин, почему статически типизированные программы обычно легче читать, чем динамически типизированные. Статическая типизация накладывает большие ограничения на автора программы, но также накладывает большие ограничения на интерпретацию программы, облегчая понимание ее кода.

Имея в виду эти аргументы, рекомендуется использовать их constтам, где это возможно, поскольку это утверждение дает нам наименьшую возможность подумать.

Источник: https://ponyfoo.com/articles/var-let-const

mrmaclean89
источник