Учебное пособие (для Javascript), которое я делаю, предлагает написать такую функцию:
function sayHello() {
//Some comments explaining the next line
window.alert("Hello");
}
Помимо обфускации, есть ли польза от написания чего-то подобного в реальной жизни? Если да, каковы преимущества?
language-agnostic
functions
Даниил
источник
источник
Ответы:
Пожалуйста, простите мою память, если у меня есть это неправильно ... Javascript не мой предпочтительный язык реализации.
Есть несколько причин, по которым можно хотеть, чтобы функция без аргументов заключалась в вызове другой функции. В то время как простой вызов
window.alert("Hello");
- это то, что вы можете себе представить, просто вместо того, чтобы звонить напрямуюsayHello()
.Но что, если это еще не все? У вас есть дюжина мест, куда вы хотите позвонить
sayHello()
и написалиwindow.alert("Hello");
вместо этого. Теперь вы хотите это сделатьwindow.alert("Hello, it is now " + new Date())
. Если вы завершили все эти звонки, какsayHello()
вы меняете его в одном месте. Если вы этого не сделали, вы измените его в дюжине мест. Это касается не повторять себя . Вы делаете это, потому что вы не хотите делать это дюжину раз в будущем.В прошлом я работал с библиотекой i18n / l10n, которая использовала функции для локализации текста на стороне клиента. Рассмотрим
sayHello()
функцию. Вы можете распечатать его,hola
когда пользователь переведен на испанский язык. Это может выглядеть примерно так:Хотя библиотека работала не так. Вместо этого он имел набор файлов, которые выглядели так:
И тогда библиотека обнаружит настройку языка браузера и затем создаст динамические функции с соответствующей локализацией в качестве возвращаемого значения для вызова функции без аргументов на основе соответствующего файла локализации.
Мне не хватает Javascript-кодера, чтобы сказать, хорошо это или плохо ... просто так было и можно рассматривать как возможный подход.
Дело в том, что перенос вызова в другую функцию в свою собственную функцию часто весьма полезен и помогает в модульности приложения, а также может облегчить чтение кода.
Все это в стороне, вы работаете с учебником. Надо вводить вещи как можно проще с самого начала. Введение вызовов функций в стиле varargs с самого начала может привести к некоторому очень запутанному коду для человека, который вообще не знаком с кодированием. Намного легче перейти от без аргументов к аргументам, к стилю varargs - с каждым построением на предыдущих примерах и понимании.
источник
window.alert
также часто используется в качестве заполнителя во время разработки до тех пор, пока не будет спроектирован / реализован хороший модальный / всплывающий текст, так что, как и в случае с языком, его можно переключить гораздо проще Или, если у вас уже есть, обновление дизайна через несколько лет может потребовать аналогичных изменений.Я думаю, что иногда полезно скрывать реализацию.
И это дает вам возможность изменить его позже
источник
централизация: хотя реализация занимает одну строку, если она часто меняется, вы, вероятно, предпочтете изменить ее в одном месте, чем везде, где вызывается sayHello.
сведение к минимуму / скрытие зависимостей: вашему клиентскому коду больше не нужно знать, что существует оконный объект, и вы даже можете изменить всю реализацию, не затрагивая клиентский код вообще
выполнение контракта: клиентский код может ожидать модуль с функцией sayHello. В этом случае, даже если это тривиально, функция должна быть там.
согласованность уровней абстракции: если в клиентском коде используются высокоуровневые операции, то в ваших интересах писать клиентский код в терминах 'sayHello, sayBye' и некоторых других функций 'sayXXX' вместо оконных объектов. На самом деле, в клиентском коде вы можете даже не знать, что существует такая вещь, как «оконный» объект.
источник
Удивительно, что ни один другой человек не упомянул о тестировании.
Конкретная «завернутая» строка, которую вы выбрали, на
window.alert('hello')
самом деле является прекрасным примером этого. Все, что связано сwindow
объектом, очень, очень больно проверять. Умножьте это на 1000 раз в своем приложении, и я гарантирую, что разработчики в конечном итоге откажутся от тестирования. С другой стороны, довольно просто забитьsayHello
функцию шпионом и проверить, что она была вызвана.Более практичный пример - потому что действительно, кто на самом деле использует
window.alert(...)
в производственном коде? - проверяет системные часы. Так, например, это будет переносDateTime.Now
в .NET,time(...)
в C / C ++ илиSystem.currentTimeMillis()
в Java. Вы действительно хотите заключить тех в зависимость, которую вы можете внедрить, потому что их не только (почти) невозможно высмеять / подделать, они доступны только для чтения и не являются детерминированными . Любой тест, охватывающий функцию или метод, который непосредственно использует функцию системных часов, с большой вероятностью будет подвержен периодическим и / или случайным сбоям.Настоящая обертка - это однострочная функция,
return DateTime.Now
но это все, что вам нужно для того, чтобы взять плохо спроектированный, непроверяемый объект и сделать его чистым и проверяемым. Вы можете заменить поддельные часы на обёртку и установить время, какое хотите. Проблема решена.источник
Как сказал Доваль, этот пример, вероятно, просто пытается познакомить вас с функциями. Я вообще, хотя, это полезно. В частности, указав некоторые, но не все аргументы, и передав другие, вы можете сделать более специфическую для конкретного случая функцию из более общей функции. В качестве несколько тривиального примера рассмотрим функцию сортировки, которая принимает массив для сортировки и функцию сравнения для сортировки. Указав функцию сравнения, которая сравнивает по числовому значению, я могу создать функцию sortByNumericValue, и вызовы этой функции будут намного более четкими и краткими.
источник
Мышление, стоящее за вашим вопросом, кажется: «Почему бы просто не написать
alert("Hello");
прямо? Это довольно просто».Отчасти ответ заключается в том, что вы действительно не хотите звонить
alert("Hello")
- вы просто хотите поздороваться.Или: Зачем хранить контакты на вашем телефоне, когда вы можете просто набирать телефонные номера? Потому что вы не хотите помнить все эти цифры; потому что набор номеров утомителен и подвержен ошибкам; потому что число может измениться, но это все тот же человек на другом конце. Потому что ты хочешь звонить людям , а не номерам.
Это то, что понимается под такими терминами, как абстракция, косвенное обращение, «скрытие деталей реализации» и даже «выразительный код».
То же самое относится и к использованию констант вместо записи необработанных значений везде. Вы можете просто написать
3.141592...
каждый раз, когда вам нужно π, но, к счастью, естьMath.PI
.Мы могли бы также посмотреть на
alert()
себя. Кого волнует, как он создает и отображает это диалоговое окно с предупреждением? Вы просто хотите предупредить пользователя. Между вами пишуalert("Hello")
и изменением пикселей на экране, существует глубокий, глубокий стек кода и аппаратного обеспечения, при котором каждый слой сообщает следующему, чего он хочет, и этот следующий уровень заботится о деталях, пока максимально глубокий слой не перевернет несколько битов в видеопамятьВы действительно не хотите делать все это сами, чтобы просто поздороваться.
Программирование - ну, на самом деле, любая задача - сводится к разбивке сложных проблем на управляемые куски. Решение каждого куска дает вам строительный блок, и с помощью достаточно простых строительных блоков вы можете строить большие вещи.
Это алгебра.
источник
Рекомендуется хранить вычисление значений (выражений) отдельно от выполнения действий (выражений). Нам нужен точный контроль над тем, где и когда будут предприняты действия (например, отображение сообщений), но при расчете значений мы предпочли бы работать на более абстрактном уровне и не должны заботиться о том, как эти значения рассчитываются.
Функция, которая только вычисляет возвращаемое значение, используя только аргументы, которые она дает, называется чистой .
«Функция», которая выполняет действие, на самом деле является процедурой , которая оказывает влияние .
Любые эффекты, возникающие при вычислении значения, называются побочными эффектами , и лучше избегать их, где это возможно («Мне просто нужна была эта строка, я не знал, что это приведет к разрушению базы данных!»).
Чтобы свести к минимуму вероятность побочных эффектов, мы должны избегать отправки слишком большого количества данных в наши процедуры или каких-либо расчетов в них; если какое-то вычисление необходимо выполнить заранее, обычно лучше сделать это отдельно в чистой функции, а затем передать в процедуру только требуемый результат. Это сохраняет цель процедуры ясной и снижает вероятность того, что она будет позже использована позже как часть вычисления (вместо этого можно использовать чистую функцию).
По той же причине мы должны избегать обработки результатов внутри процедуры. Лучше вернуть результат (если есть) нашего нашего действия и выполнить любую последующую обработку с чистыми функциями.
Если мы будем следовать этим правилам, мы можем получить такую процедуру
sayHello
, которая не требует каких-либо данных и не дает результата. Следовательно, лучший интерфейс для этого - не иметь аргументов и не возвращать значение. Это предпочтительнее, например, для вызова «console.log» во время некоторых вычислений.Чтобы уменьшить потребность в эффектах во время вычислений, у нас могут быть вычисления, которые возвращают процедуры ; например. если нам нужно определиться с действием, которое нужно предпринять, мы можем иметь чистую функцию, которая выбирает процедуру и возвращает ее, а не выполняет ее напрямую.
Аналогично, чтобы уменьшить потребность в вычислениях во время процедур, у нас могут быть процедуры, принимающие другие процедуры в качестве параметров (возможно, результат функции); например. взятие множества процедур и выполнение одной за другой.
источник
setFoo
звонки, так как это подразумевает изменяемые данные. Изменение содержимого переменных / свойств является эффектом, который приводит к тому, что все вычисления, использующие эти данные, становятся нечистыми. Я бы не рекомендовалexecute
вызовы как таковые, но я бы порекомендовалrunFoo
процедуры для выполнения действий на основе их аргументов.Я бы сказал, что это сочетание ответов, данных @MichaelT и @Sleiman Jneidi.
Возможно, в коде есть несколько мест, где вы хотите поприветствовать пользователя сообщением Hello, чтобы вы упаковали эту идею в метод. В методе вы можете перевести его или расширить простое «Привет», отображая более длинный текст. Также вы можете захотеть использовать приятный диалог JQuery вместо предупреждения.
Дело в том, что реализация находится в одном месте. Вам просто нужно изменить код в одном месте. (SayHello (), возможно, слишком простой пример)
источник