Ленивый, компонуемый и модульный JavaScript

Хорошей практикой считается делать код компонуемым и модульным. Он упрощается и к его частям становится проще обращаться несколько раз. Для JavaScript-разработчиков тоже появились инструменты для использования этого подхода.

Остановимся на использовании четырех возможностей ECMAScript: итераторах, генераторах, «жирных» стрелочных функциях и операторе for-of в сочетании с функциями высшего порядка, композициями функций, отложенными вычислениями.

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

Функции высшего порядка

Функция высшего порядка — это функция, которая удовлетворяет хотя бы одному из условий:

  • принимает в качестве аргументов одну или более функций;
  • возвращает функцию как результат.

Вы наверняка сталкивались с функциями высшего порядка, если писали обработчик событий или применяли Array.prototype.map().

Например, функция, попадая в Array. prototype.map, ничего не знает о её структуре и методах. Единственное знание — механизм обработки своих входящих данных, поэтому может быть неоднократно применима как для отдельных значений, так и коллекций.

Композиции функций

Композиция функций — применение одной функции к результату другой. В результате чего из простых функций составляются сложные.

Например, есть две функции: f и g. Результат композиции (f, g) — функция f(g(x)), которую так же можно использовать в композиции или передать как параметр функции высшего порядка.

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

В монолитном решении, представленном ниже, используется новый оператор for-of вместо привычного for-loop для перебора значений массива. Итератор — контейнер, который реализует протокол последовательного перебора и возвращает с помощью оператора yield значения по одному (массивы, строки, генераторы и т. д.).

function vowelCount(file) {
  let contents = readFile(file)
  let lines = contents.split('\n') // преобразуем содержимое в массив строк.
  let result = [] // массив массивов, где каждый индекс соответствует строке
                  // и каждый индекс в пределах массива — кол-во гласных.

  for (let line of lines) {
    let temp = []
    let words = line.split(/\s+/)

    for (let word of words) {
      let vowelCount = 0

      for (let char of word) {
        if (
          'a' === char || 'e' === char || 'i' === char || 'o' === char || 'u' === char
        ) vowelCount++
      }
      temp.push(vowelCount)
    }
    result.push(temp)
  }
  return result
}

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

// main.js
function vowelOccurrences(file) {
  return map(words => map(vowelCount, words), listOfWordsByLine(read(file)))
}

function vowelCount(word) {
  return reduce((prev, char) => {
    if (
      'a' === char || 'e' === char || 'i' === char || 'o' === char || 'u' === char
    ) return ++prev
    else return prev
  }, 0, word)
}

function listOfWordsByLine(string) {
  return map(line => split(/\s+/, line), split('\n', string))
}
// повторно используемые функции из библиотеки util.js
function reduce(fn, accumulator, list) {
  return [].reduce.call(list, fn, accumulator)
}

function map(fn, list) {
  return [].map.call(list, fn)
}

function split(splitOn, string) {
  return string.split(splitOn)
}

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

Например:

let input = 'line one\nline two'
listOfWordsByLine(input) // [['line','one'],['line','two']]

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

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

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

Отложенные вычисления

Отложенные («ленивые») вычисления — операции, выполнение которых откладывается до тех пор, пока не нужен результат.

Рассмотрим на примере «ленивую» обработку данных и построение «ленивых» цепочек вычислений (pipelines).

Дан список целых чисел. Необходимо возвести в квадрат элементы списка и вывести сумму первых четырех полученных значений.

Для написания «ленивой» реализации выясним, когда понадобится произвести вычисления. При суммировании первых четырёх квадратов нужно возвести в квадрат эти элементы, поэтому операцию возведения в квадрат отложим до начала суммирования.

let squareAndSum = (iterator, n) => {
  let result = 0

  while(n > 0) {
    try {
      result += Math.pow(iterator.next(), 2)
      n--
    }
    catch(_) {
      // длина перечня меньше `n` следовательно
      // iterator.next сообщает, что у него нет значений
      break
    }
  }
  return result
}

let getIterator = (arr) => {
  let i = 0

  return {
    next: function() {
      if (i < arr.length) return arr[i++]
      else throw new Error('Iteration done')
    }
  }
}

let squareAndSumFirst4 = (arr) => {
  let iterator = getIterator(arr)

  return squareAndSum(iterator, 4)
}

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

За счёт контроля итерации и yield обрабатываются только те элементы, которые будут участвовать в итоге. Итерация реализуется таким образом, что элементы возвращаются с помощью оператора yield по одному вплоть до получения сигнала об отсутствии элементов для вывода. Протокол инкапсулируется в объект итератора, который содержит одну функцию — next, принимающую нулевые значения. Следующий элемент возвращается, только при наличии элементов.

Функция squareAndSum принимает в качестве входных данных итератор и

n (число элементов в сумме). С помощью вызова метода .next() n раз получает из итератора n значений, возводит каждый из элементов в квадрат и суммирует их.

GetIterator возвращает итератор, сформированный из нашего списка.

squareAndSumFirst4 использует getIterator и squareAndSum, чтобы вернуть сумму первых четырех чисел из входного списка, возведённых в квадрат «ленивым» способом. Использование итераторов позволяет внедрять структуры данных, которые могут вернуть с помощью оператора

yield бесконечные значения.

Необходимость выполнения описанных выше действий каждый раз, когда нам нужен итератор, усложняет написание кода. К счастью, ES, начиная с версии 6, предлагает простой способ описания итераторов — генераторы.

Генератор — функция, работу которой можно приостановить, а потом возобновить. Причём генератор может выдать значения несколько раз в ходе исполнения с помощью ключевого слова yield. При вызове возвращает объект-генератор. С помощью метода .next получается следующее значение. В JavaScript генераторы создаются путём определения функции с *.

// генератор, который возвращает бесконечный список последовательных
// чисел, начиная с 0
// знак "*" тспользуется, чтобы сообщить обработчику, что это генератор
function* numbers() {
  let i = 0

  yield 'бесконечный список чисел'
  while (true) yield i++
}

let n = numbers() // получить итератор от генератора
n.
next() // {value: "бесконечный список чисел", done: false} n.next() // {value: 0, done: false} n.next() // {value: 1, done: false} // и так далее..

Генераторы поддерживают оба протокола, поэтому получить значения можно с помощью оператора for-of.

for (let n of numbers()) console.log(n) // печатать бесконечный список чисел

Теперь реализуем задачу, которая покажет, как эти три подхода помогают очистить код приложения.

Пример: задача и решение

Исходные данные:

  • файл, который на каждой строке содержит имя пользователя и по размеру превышает объём оперативной памяти используемого устройства;
  • функция, которая считывает блок данных с диска и возвращает его же, дополнив символом новой строки.

Задача:

  1. Получить имена пользователей, которые начинаются с «A», «E» или «M».
  2. Выполнить запрос с использованием полученных данных к странице http://jsonplaceholder.
    typicode.com/users?username=<username>
    .
  3. Применить к первым четырём ответам сервера заданный набор из четырёх функций.

Содержимое файла:

Bret
Antonette
Samantha
Karianne
Kamren
Leopoldo_Corkery
Elwyn.Skiles
Maxime_Nienow
Delphine
Moriah.Stanton

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

  1. Первая возвращает каждое имя (getNextUsername).
  2. Вторая отбирает имена, которые начинаются с «A», «E»или «M» (filterIfStartsWithAEOrM).
  3. Третья делает сетевой запрос и возвращает Promise, объект-заглушку для вывода результата вычисления (makeRequest).

Эти функции оперируют значениями. Для того, чтобы применить их к списку, введём три функции высшего порядка:

  1. Первая выбирает элементы списка на основе заданных параметров (filter).
  2. Вторая применяет функцию к каждому элементу списка (map).
  3. Третья применяет функции из одного итератора к данным другого итератора (zipWith c функцией упаковки).

«Ленивость» этого подхода может принести пользу, так как сетевые запросы делаются не для всех подходящих под критерии фильтрации имен.

Итак, у нас есть массив функций, которые должны выполняться для обработки окончательных ответов, и функция, которая возвращает «ленивым» способом блоки данных. Напишем функцию с применением генераторов для получения имен пользователей, используя «ленивый» подход.

// функции, которые выполняются в ответ на запрос
let fnsToRunOnResponse = [f1, f2, f3, f4]

// возвращает следующий блок данных из файла
// символ * обозначает, что эта функция является генератором в JavaScript
function* getNextChunk() {
  yield 'Bret\nAntonette\nSamantha\nKarianne\nKamren\nLeopoldo_Corkery\nElwyn.Skiles\nMaxime_Nienow\nDelphine\nMoriah. Stanton\n'
}

// getNextUsername принимает итератор, который возвращает следующий фрагмент, заканчивающийся переводом строки
// он сам возвращает итератор, который возвращает имена по одному
function* getNextUsername(getNextChunk) {
  for (let chunk of getNextChunk()) {
    let lines = chunk.split('\n')

    for (let l of lines) if (l !== '') yield l
  }
}

Теперь для работы со значениями необходимы следующие функции:

  1. Первая возвращает True, если значение удовлетворяет критериям фильтра, False — в противном случае.
  2. Вторя возвращает URL-адрес при получении имени пользователя.
  3. Третья при получении URL-адреса делает запрос и возвращает Promise для этого запроса.

Promise — «контейнер» для хранения значения выполняемой операции, которое появится в будущем. Интерфейс Promise позволяет определить, какие действия выполнять после успешного завершения операции или сбоя. Если операция пройдёт успешно, вызывается обработчик удачного результата со значением операции. В противном случае вызывается обработчик ошибки.

// эта функция возвращает True, если имя пользователя соответствует нашим критериям
// и false в противном случае
let filterIfStartsWithAEOrM = username => {
  let firstChar = username[0]

  return 'A' === firstChar || 'E' === firstChar || 'M' === firstChar
}

// makeRequest делает AJAX-запрос к URL и возвращает promise
// он использует новый API и fat arrows es6
// это обычная функция, не генератор
let makeRequest = url => fetch(url).then(response => response.json())

// makeUrl принимает имя пользователя и генерирует URL-адрес, к которому хотим обратиться
let makeUrl = username => 'http://jsonplaceholder.typicode.com/users?username=' + username

Теперь напишем функции высшего порядка, которые обеспечат работу с «ленивыми» списками. Их задача — отложить выполнение до тех пор, пока не появится запрос. В этом случае нужны значения по требованию, поэтому на помощь придут генераторы.

// функция filter принимает другую функцию (предикат). Предикат же принимает значение и возвращает
// булевое значение и сам итератор. Filter возвращает итератор, если предикат при обработке
// входного значения возвращает True.
function* filter(p, a) {
  for (let x of a)
    if (p(x)) yield x
}


// map принимает на входе функцию и итератор
// возвращает новый итератор, который возвращает результат применения функции к каждому значению
// входного итератора
function* map(f, a) {
  for (let x of a) yield f(x)
}

// zipWith принимает булеву функцию и два итератора в качестве входных данных
// возвращает итератор, который в свою очередь применяет заданную функцию к значениям из каждого
// итератора и выдаёт результат
function* zipWith(f, a, b) {
  let aIterator = a[Symbol.iterator]()
  let bIterator = b[Symbol. iterator]()
  let aObj, bObj

  while (true) {
    aObj = aIterator.next()
    if (aObj.done) break
    bObj = bIterator.next()
    if (bObj.done) break
    yield f(aObj.value, bObj.value)
  }
}

// execute запускает отложенный итератор
// как правильно неоднократно обращается к `.next` итератора
// вплоть до выполнения итератора
function execute(iterator) {
  for (x of iterator) ;; // извлекаем значения итератора
}

Необходимые функции написаны. Используем композицию, чтобы решить поставленную задачу.

let filteredUsernames        = filter(filterIfStartsWithAEOrM, getNextUsername(getNextChunk)

let urls                     = map(makeUrl, filteredUsernames)

let requestPromises          = map(makeRequest, urls)

let applyFnToPromiseResponse = (fn, promise) => promise.then(response => fn(response))

let lazyComposedResult       = zipWith(applyFnToPromiseResponse, fnsToRunOnResponse, requestPromises)

execute(lazyComposedResult)

lazyComposedResult — «ленивая» цепочка вычислений (pipeline), составленная из композиций функций. Ни одно звено не выполнится, пока не запущен верхний блок композиции, то есть lazyComposedResult. Мы сделали только четыре вызова, хотя результат фильтрации может содержать более четырех значений.

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

Перевод статьи «Lazy, composable, and modular JavaScript»

Обзор функций в JavaScript ES6.


В течение последних нескольких лет JavaScript изменялся. И вот 12 новых фичей, которые вы можете начать использовать уже сегодня!

1.    История JavaScript

Новые дополнения к языку называются ECMAScript 6. Они также упоминаются как ES6 или ES2015+. Начиная с концепции 1995 года, JavaScript развивался медленно. Новые дополнения выходили раз в несколько лет. ECMAScript появился в 1997 году, чтобы указать путь JavaScript. Были выпущены такие его версии: ES3, ES5, ES6 и другие.


 

Как вы заметили, между ES3, ES5 и ES6 существуют промежутки в 10 и 6 лет. Новая стратегия состоит в том, чтобы делать небольшие постепенные изменения каждый год. Вместо того, чтобы делать большие изменения сразу, как это случилось с ES6.

2.    Поддержка браузеров

Все современные браузеры и среды программирования уже поддерживают ES6!


 

Chrome, MS Edge, Firefox, Safari, Node и многие другие уже имеют встроенную поддержку большинства функций JavaScript ES6. Таким образом, всё, что вы собираетесь изучить в этом туториале, вы можете начать использовать прямо сейчас. Давайте начнем с ECMAScript 6!

3.    Основные функции ES6

Вы можете проверить все эти фрагменты кода на консоли своего браузера.


 

Так что не верьте мне на слово и тестируйте каждый пример ES5 и ES6.

3.1. Блочная область видимости переменных

В ES6 мы перешли от объявления переменных с var на использование let/const.

Что не так с var? Проблема var – это утечка переменной в другой блок кода, например, в циклы for или if-блоки.


 

Для test(false) вы ожидаете возвращения outer, но нет, вы получаете undefined. Почему?

Потому что даже при том, что if-блок не выполняется, выражение var x в строке 4 «поднимается».

Поднятие переменных:

  • var является переменной области видимости. Она доступна во всей функции даже до того, как её объявят.
  • Выражения «поднимаются». Так что вы сможете использовать переменные до их объявления.
  • Инициализация НЕ поднимется. Если вы используете var, ВСЕГДА объявляйте ваши переменные наверху.
  • После применения правил подъема, мы можем лучше понять, что же случилось.


 

  • ECMAScript 2015 идёт на помощь:


 

Изменение var на let приводит к тому, что всё работает так, как и ожидалось. Если блок if не вызывается, переменная x не поднимается из блока.

Взглянём на поднятие и «временные мёртвые зоны»:

  • В ES6 let будет поднимать переменную наверх блока (НЕ наверх функции, как это происходит в ES5).
  • Однако ссылка на переменную в блоке перед объявлением этой переменной приводит к ReferenceError.
  • let – переменная области видимости. Вы не можете использовать её, пока она не будет объявлена.
  • «Временные мёртвые зоны» – это зоны в начале блока и до того места, где объявляется переменная.

IIFE (Immediately-Invoked Function Expression)

Перед объяснением IIFE взгляните на пример:


 

Как вы видите, появляется private. Для того, чтобы удержать его, вам необходимо использовать IIFE (немедленно-вызываемое выражение функции):


 

Если вы посмотрите на jQuery/lodash или другие open source проекты, то заметите, что они используют IIFE во избежание загрязнения глобальной  среды и определения только глобального, например _,$ или jQuery.

ES6 гораздо проще, нам больше не нужно использовать IIFE, когда мы просто можем применить блоки и let:


 

Const

Вы также можете использовать const, если не хотите, чтобы переменная изменялась вообще.


 

3.2. Литералы шаблонов

Нам больше не нужно встраивать конкатенации, когда у нас есть литералы шаблонов. Взгляните:

Сейчас вы можете использовать кавычку (`) и строковую интерполяцию ${}:


 

3.3. Многострочные строки

Нам больше не нужно конкатенации строк + \n по типу:


 

В ES6 мы снова можем использовать кавычку для решения такого примера:


 

Оба фрагмента кода будут иметь точно такой же результат.

3.4. Назначение деструктуризации

Деструктуризация в ES6 очень полезная и точная.

Получение элементов с массива


 

То же самое:


 

Обмен значений


 

Так же:


 

Деструктуризация для нескольких возвращаемых значений


 

В строке 3 вы также можете вернуть ее в массив подобный тому, что на примере (и сохранить некоторые, набрав код):


 

Но потом необходимо подумать о порядке возврата данных.


 

В ES6 вызывающий выбирает только те данные, которые ему нужны (строка 6):


 

Обратите внимание: В строке 3 есть некоторые другие функции ES6. Мы можем сжать { left: left} только до { left}.Посмотрите, насколько это компактнее по сравнению с версией ES5. Разве не круто?

Деструктуризация для параметров согласования


 

Так же, но короче:


 

Deep Matching


 

Так же, но короче:


 

Это также называют деструктуризацией объектов.

Как видите, деструктуризация весьма полезна и способствует хорошему стилю программирования.

Практический опыт:

  • Используйте деструктуризацию массива для получения элементов или замены переменных. Это избавит вас от создания временных ссылок.
  • Не используйте деструктуризацию массива для нескольких возвращаемых значений, вместо этого примените деструктуризацию объекта.

3.

5. Классы и Объекты

С ECMAScript 6 мы перешли от «функции-конструктора» к «классам».

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

В ES5 мы использовали объектно-ориентированное программирование (ООП), применяя функцию- конструктор для создания объектов, следующим образом:

Видео курсы по схожей тематике:

Создание адаптивного SPA с Angular

Сергей Патёха

Платформа Managed Extensibility Framework (MEF)

Давид Бояров

Photoshop. Базовый курс для web-разработчика

Сергей Воропаев


 

В ES6 имеется некий синтаксический сахар. Мы можем делать то же самое менее шаблонно и с новыми ключевыми словами, такими как class и constructor. Также обратите внимание на то, как мы определяем методы constructor.prototype. speak = function () vs speak():


 

Как видим, оба стиля (ES5/6) дают одинаковые результаты и используются одинаково.

Практический опыт:

  • Всегда используйте синтаксис класса и избегайте прямого манипулирования прототипом. Почему? Потому что это делает код более кратким и понятным.
  • Избегайте наличия пустого конструктора. Классы имеют конструктор по умолчанию, если он не указан.

3.6. Наследование

Опираемся на предыдущий класс Animal. Предположим, мы хотим расширить его и определить класс Lion.

В ES5 это большей частью связано с прототипическим наследованием.


 

Я не буду описывать все детали, но заметьте:

  • В строке 3 мы явно вызываем конструктор Animal с параметрами.
  • В строках 7-8 мы назначили прототип Lion прототипу Animal.
  • В строке 11 мы вызываем метод speak из родительского класса Animal.

В ES6 у нас есть новые ключевые слова extends и super.


 

Посмотрите, насколько разборчиво выглядит этот код ES6 по сравнению с ES5, и они работают одинаково!

Практический опыт:

  • Используйте встроенный способ наследования с extends.

3.7. Native Promises

Мы перешли от callback hell к promises.


 

У нас есть одна функция, которая при done получает обратный вызов для выполнения. Мы должны выполнить этот вызов дважды один за другим. Вот почему во второй раз мы вызываем printAfterTimeout.

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


 

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

3.8. Стрелочные функции

ES6 не удалил выражения функций, но добавил новые функции – стрелочные.

В ES5 были некоторые проблемы с this:


 

Вам нужно использовать временное this для ссылки внутри функции или использовать bind. В ES6 вы можете использовать стрелочную функцию.


 

3.9. For…of

Мы перешли от for к forEach, и потом к for…of:


 

В ES6 for…of также позволяет нам делать итерации.


 

3.10.  Параметры по умолчанию

Мы перешли от проверки того, была ли переменная определена, к присвоению значения параметрам по умолчанию (default parameters). Вы делали что-то подобное раньше?


 

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

  • В строке 8 мы задали 0, 0  и получили 0, -1
  • В строке 9 мы задали false, но получили true.

Если в качестве параметра по умолчанию задано значение boolean или это значение равно нулю, то оно не будет работать. Знаете почему? Все расскажем после примера ES6. С ES6 вы можете писать код лучше и короче!

Обратите внимание на строки 5 и 6 – мы получаем ожидаемые результаты. Пример ES5 не работает. Сначала мы должны проверить undefined, поскольку false, null, undefined и 0 являются фальшивыми значениями. Мы можем выбраться с такими цифрами:


 

Сейчас всё работает так, как и должно, когда мы проверяем undefined.

3.11. Rest-параметры

Мы перешли от аргументов к rest-параметрам и spread-оператору. Получать произвольное количество аргументов на ES5 довольно неудобно:


 

Мы можем сделать то же, используя rest-оператор . . . .


 

3.12. Spread-оператор

Бесплатные вебинары по схожей тематике:

Создание дизайна лендинга с Figma.

Алла Штогрина

Что надо знать для веб разработки. (реальная разработка + обзор вакансий)»

Михаил Храбан

Firebase. Организация удаленной работы с данными.

Тысячный Влад

 Мы пришли от apply() до spread-оператора. Опять на помощь приходит . . .:

Напоминание: мы используем apply () для преобразования массива в список аргументов. Например, Math.max () принимает список параметров, но, если у нас есть массив, мы можем использовать apply, чтобы заставить его работать.


 

Как мы видели ранее, мы можем использовать apply для передачи массивов в виде списка аргументов:
 

В ES6 вы можете использовать spread-оператор:


 

Кроме того, мы пришли от использования массивов contact к использованию spread-оператора:


 

В ES6 вы можете сглаживать вложенные массивы, используя оператор spread:


 

4.    Заключение

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


Материал подготовлен на основе статьи из блога Adrian Mejia

Функции Js — Learn.

co

Цели

  1. Написать функцию, которая возвращает значение
  2. Напишите функцию, которая принимает параметр
  3. Напишите функцию, которая принимает несколько параметров

Введение

Вы будете писать свое решение на index.js .

В этой лабораторной работе мы будем развивать наши навыки общения с помощью JavaScript. У нас праздничное настроение, поэтому мы собираемся подвести итоги общих праздничных поздравлений. как функции, чтобы нам не приходилось повторяться. Красота функций заключается в том, что мы могли бы повторно использовать эти функции для текста поздравительных открыток, для устные приветствия, тексты песен и т. д…

Шаблонные литералы

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

 var date = "3 июля"
 

В JavaScript мы можем использовать операторы для конкатенации (объединения) двух строк или, в данном случае, строки и переменной, например:

 console. log("Мой день рождения " + дата)
 

При заданной дате приведенный выше код будет регистрировать Мой день рождения 3 июля . Однако, используя слегка измененный синтаксис, мы можем добиться того же, вставив переменную в строку. Они называются шаблонными литералы и переписав приведенный выше console.log с одним, будет выглядеть так:

 console.log(`Мой день рождения ${date}`)
 

Это также запишет Мой день рождения 3 июля .

Теперь есть два важных изменения в синтаксисе: Любые переменные, которые мы хотим include должен быть заключен в фигурные скобки ( { } ) и перед ним стоит знак доллара. ($). Кроме того, вместо одиночных ' или двойных кавычек ' мы должен использовать обратные кавычки, ` . Если обратные кавычки не используются, JavaScript будет интерпретировать знак доллара и фигурные скобки как обычную часть строки , в результате получается Мой день рождения ${date} ! Любое выражение может быть включено в литералы шаблона, а не только переменные, поэтому мы могли бы написать что-то вроде:

 console. log(`У меня есть ${1 + 1} питомцы`)
 

И получить У меня есть 2 питомца . Обратите внимание, что это не будет регистрировать то же самое, если вы сделали следующее:

 console.log("У меня есть " + 1 + 1 + " домашние животные")
 

Это логи У меня 11 домашних животных ! JavaScript преобразует оба 1 в строки, а не сначала складывает их вместе. Вам нужно будет написать следующее, чтобы получить тот же результат, что и литералы шаблона:

 console.log("У меня есть " + (1 + 1) + " домашние животные")
 

Вы можете использовать операторы или литералы шаблонов для построения больших строк с динамическими значениями. Литералы шаблонов — это просто способ сделать ваш код немного легче читать и помочь гарантировать, что JavaScript не интерпретируется неправильно, когда объединение различных типов данных в строки, как мы только что видели.

Инструкции

  1. Напишите функцию с именем happyHolidays . Эта функция не должна принимать параметры и должны вернуть строку "С праздником!" .

  2. Напишите функцию с именем happyHolidaysTo . Эта функция должна принимать параметр имени человека, которого вы хотите поздравить с праздником, и вернуть строку `Счастливых праздников, ${name}!`

  3. Напишите функцию с именем happyCustomHolidayTo . Эта функция должна принимать два параметры, праздник, в который хотите пожелать удачи, и название человек, которому вы желаете добра. Порядок параметров имеет значение, поэтому обязательно сначала укажите праздник, а затем имя. Эта функция должна возвращать строку `С праздником ${праздник}, ${имя}!`

  4. Напишите функцию с именем HolidayCountdown . Эта функция должна принимать два параметры, название праздника и количество дней до него. функция должна возвращать строку `До ${дней} дней до ${праздника}!` . Обратите внимание, что хотя дней используется первым при построении возвращаемой строки, holidayCountdown должен сначала введите название праздника, а затем количество дней до него.

Функции | Formula.js

557068005557068005, 3,5, 1,2, правда)

7381804
АВЕДЕВ

АВЕДЕВ([2,4],[8,16])

4,5
СРЕДНЯЯ

СРЕДНЕЕ([2,4], [8,16])

7,5
СРЕДНЯЯ

СРЗНАЧA([2,4], [8,16])

7,5
СРЕДНИЙЕСЛИ

СРЗНАЧЕСЛИ([2,4,8,16], '>5', [1, 2, 3, 4])

3,5
СРЕДНИЕ

СРЗНАЧЕСЛИМН([2,4,8,16], [1,2,3,4], '>=2', [1,2,4,8], '

6
БЕТАДИСТ

БЕТАРАСП(2, 8, 10, правда, 1, 3)

0,6854705810117458
БЕТАИНВ

6854705810117458, 8, 10, 1, 3)"> БЕТАИНВ(0,6854705810117458, 8, 10, 1, 3)

1.9999999999999998
БИНОМРАСП

БИНОМРАСП(6, 10, 0,5, ложь)

0,205078125
КОРРЕЛ

КОРРЕЛ([3,2,4,5,6], [9,7,12,15,17])

0,9970544855015815
СЧЕТ

СЧЁТ([1,2], [3,4])

4
КОНТА

СЧЁТ([1, ноль, 3, 'а', '', 'с'])

4
СЧИТАТЬ ПУСТО

СЧИТАТЬПУСТО([1, ноль, 3, 'а', '', 'с'])

2
СЧЁТЕСЛИ

СЧЁТЕСЛИ(['Кан', 'Мельбурн', 'Пало-Альто', 'Сингапур'], 'а')

3
СЧЕТИСЧИСЛ

СЧЁТЕСЛИМН([2,4,8,16], [1,2,3,4], '>=2', [1,2,4,8], '

2
СТРАНА УНИКАЛЬНАЯ

СЧЁТУНИКАЛЬНЫЙ([1,1,2,2,3,3])

3
КОВАРИАЦИЯP

КОВАРИАЦИЯP([3,2,4,5,6], [9,7,12,15,17])

5. 2
КОВАРИАНТЫ

КОВАРИАНТЫ([2,4,8], [5,11,12])

9,666666666666668
DEVSQ

ДЕВСК ([2,4,8,16])

115
ЭКСПОНДИСТ

ЭКСПОНДРАСП(0,2, 10, истина)

0,8646647167633873
FРАСП

2069, 6, 4, false)"> FРАСП(15.2069, 6, 4, ложь)

0,0012237917087831735
ФИНВ

ФИНВ(0,01, 6, 4)

0,10930991412457851
ФИШЕР

ФИШЕР(0,75)

0,9729550745276566
ФИШЕРИНВ

ФИШЕРИНВ(0,9729550745276566)

0,75
ПРОГНОЗ

ПРОГНОЗ(30, [6,7,9,15,21], [20,28,31,38,40])

10. 607253086419755
ЧАСТОТА

ЧАСТОТА([79,85,78,85,50,81,95,88,97], [70,79,89])

1,2,4,2
ГАММА

ГАММА(2.5)

1.32934039143
ГАММАЛН

ГАММАЛН(10)

12.801827480081961
ГАУСС

ГАУСС(2)

0,4772498680518208
ГЕОМЕАН

ГЕОМЕАН([2,4], [8,16])

5. 656854249492381
РОСТ

РОСТ([2,4,8,16], [1,2,3,4], [5])

32.00000000000003
ХАРМЕЙН

ХАРМААН([2,4],[8,16])

4.266666666666667
ГИПЕОМРАСП

ГИПЕРРАСП(1, 4, 8, 20, ложь)

0,36326109387
ПЕРЕХВАТ

ПЕРЕХВАТ([2,3,9,1,8], [6,5,11,7,5])

0,04838709677419217
КУРТ

КУРТ([3,4,5,2,3,4,5,6,4,7])

-0,15179963720841627
БОЛЬШОЙ

БОЛЬШОЙ([3,5,3,5,4,4,2,4,6,7], 3)

5
ЛИНЕЙН

ЛИНЕЙН([1,9,5,7], [0,4,2,3], истина, истина)

2,1
ЛОГНОРМРАСП

5, 1.2, true)"> ЛОГНОРМРАСП(4, 3,5, 1,2, истина)

0,03
ЛОГНОРМИНВ

LOGNORMINV(0,03

4.000000000000001
МАКС

МАКС([0,1,0,2], [0,4,0,8], [истина, ложь])

0,8
МАКСА

MAXA([0. 1,0.2], [0.4,0.8], [истина, ложь])

1
МЕДИАНА

МЕДИАНА([1,2,3], [4,5,6])

3,5
МИН

МИН([0.1,0.2], [0.4,0.8], [истина, ложь])

0,1
МИНА

МИНА([0.1,0.2], [0.4,0.8], [истина, ложь])

0
МОДЕМУЛЬТ

МОДЕМУЛЬТ([1,2,3,4,3,2,1,2,3])

2,3
МОДЕСНГЛ

МОДЕСНГЛ([1,2,3,4,3,2,1,2,3])

2
НОРМРАСП

5, true)"> НОРМРАСП(42, 40, 1,5, истина)

0,87802741321
НОРМИНВ

НОРМИНВ(0,

87802741321, 40, 1,5)

42
НОРМРАСП

НОРМРАСП(1, истина)

0,8413447460685429
НОРМСТОБР

НОРМСТОБР(0,8413447460685429)

1. 0000000000000002
ПИРСОН

ПИРСОН([9,7,5,3,1], [10,6,1,5,3])

0,6993786061802354
ПРОЦЕНТИЛЬEXC

ПРОЦЕНТИЛЬИСКЛ([1,2,3,4], 0,3)

1,5
ПРОЦЕНТИЛЬ

ПРОЦЕНТИЛЬ([1,2,3,4], 0,3)

1,9
PERCENTRANKEXC

ПРОЦЕНТРАНГИСКЛ([1,2,3,4], 2, 2)

0,4
ПРОЦЕНТРАНГ

ПРОЦЕНТРАНГ([1,2,3,4], 2, 2)

0,33
ПЕРМУТ

ПЕРМУТ(100, 3)

970200
ПЕРЕСТАНОВКА

ПЕРЕСТАНОВКА(4, 3)

64
PHI

75)"> ФИ(0,75)

0,30113743215480443
ПУАССОНА

РАСП ПУАССОНА(2, 5, истина)

0,12465201948308113
ПРОБ

ПРОБ([1,2,3,4], [0.1,0.2,0.2,0.1], 2, 3)

0,4
КВАРТИЛЬEXC

КВАРТИЛЬИСКЛ([1,2,3,4], 1)

1,25
КВАРТИЛЕЙНК

КВАРТИЛЕЙНК([1,2,3,4], 1)

1,75
СРЕДНИЙ РАНГ

RANKAVG(4, [2,4,4,8,8,16], ложь)

4,5
РАНКЕК

RANKEQ(4, [2,4,4,8,8,16], ложь)

4
RSQ

RSQ([9,7,5,3,1], [10,6,1,5,3])

0,4891304347826088
НАКЛОН

СКОС([3,4,5,2,3,4,5,6,4,7])

0,3595430714067974
НАКЛОН

SKEWP([3,4,5,2,3,4,5,6,4,7])

0,303193339354144
НАКЛОН

НАКЛОН([1,9,5,7], [0,4,2,3])

2
МАЛЕНЬКИЙ

МАЛЕНЬКИЙ([3,5,3,5,4,4,2,4,6,7], 3)

3
СТАНДАРТНЫЙ

5)"> СТАНДАРТНЫЙ (42, 40, 1,5)

1.3333333333333333
СТДЕВА

СТАНДАРТ([2,4], [8,16], [истина, ложь])

6.013872850889572
СТДЕВП

СТАНДОТКЛОН([2,4], [8,16], [истина, ложь])

5.361
СТДЕВПА

СТАНДОТКЛОНПА([2,4], [8,16], [истина, ложь])

5. 489889697333535
СТАНДОТКЛОН

СТАНДОТКЛОН([2,4], [8,16], [истина, ложь])

6.191391873668904
СТЕЙКС

СТЕЙКС([2,3,9,1,8,7,5], [6,5,11,7,5,4,4])

3.305718950210041
СТЬЮДРАСП

СТЬЮДРАСП(60, 1, истина)

0,9946953263673741
ИНН

9946953263673741, 1)"> ИНВ (0,9946953263673741, 1)

59.99999999996535
ТРИММЕАН

ОБРЕЗНОЕСРЕДНЕЕ([4,5,6,7,2,3,4,5,1,2,3], 0,2)

3.7777777777777777
ВАРА

ВАРА([2,4], [8,16], [истина, ложь])

36.16666666666667
ВАРП

VARP([2,4], [8,16], [истина, ложь])

28,75
ВАРПА

ВАРПА([2,4], [8,16], [истина, ложь])

30.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *