JavaScript

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

 

В этой статье я попытался составить список из наименее известных функций JS. Хотя применение некоторых из данных функций недопустимо в строгом режиме (strict mode), они по-прежнему могут использоваться в JS коде. Однако, имейте в виду, я не призываю вас к тому, чтобы начать использовать все эти функции. Конечно они классные, но, скорее всего, у вас возникнет недопонимание с товарищами по команде, если вы воспользуетесь этими функциями.

Весь исходный код доступен здесь. Удачи!

Примечание: Я не включил в список такие вещи, как Hoisting(поднятие), Closures (замыкания), Proxies (прокси), Prototypical inheritance (наследование), async/await, Generators (генераторы) и т.д. Потому что эти функции довольно известны, несмотря на их сложность.


 

Оператор Void

В JavaScript есть унарный оператор void. Возможно вы уже видели, что он используется как void(0) или void 0. Его единственная цель— вычислить выражение и возвратить значение undefined. Вам не обязательно использовать “0” после void — это просто условность. Вы можете использовать любое допустимое выражение, например, void <expression> и оно по-прежнему будет возвращать значение undefined.

 

Зачем создавать специальное ключевое слово, чтобы вернуть undefined, вместо того, чтобы просто вернуть undefined? Звучит чересчур сложно, не так ли?

🚩 Забавный факт

Что же, до ES5 вы могли присвоить новое значение исходному значению undefined, например,undefined = "abc", и это работало в большинстве браузеров. Отсюда и определение неопределенного (undefined)! В те дни, использование оператора void гарантировало, что вы всегда возвращаете исходный undefined.

Использование скобок в методе Constructor (Конструктор) необязательно

Да, скобки, которые мы добавляем после имени класса при вызове Constructor (Конструктора) — совершенно необязательны! (При условии, что вам не нужно передавать какие-либо аргументы Constructor (Конструктору))

Оба нижеприведенных примера кода считаются допустимым синтаксисом JS и дадут вам абсолютно одинаковый результат!

 

Скобки в функции IIFE можно пропустить

Синтаксис функции IIFE (Immediately Invoked Functional Expression)всегда был для меня немного странным.
Зачем все эти скобки?

Оказывается, дополнительные скобки нужны для того, чтобы сказать JavaScript парсеру, что предстоящий код — это Functional Expression(Функциональное выражение), а не Function (Функция). Теперь, зная об этом, можно пропустить все лишние скобки, при этом функция IIFEбудет все также исправно работать.

 

Оператор void сообщает парсеру о том, что код является Functional Expression (Функциональным выражением). Следовательно, мы можем пропустить скобки во время объявления функции (function definition). И знаете что еще? Мы можем использовать любые унарные операторы ( void, +, !, -, и т.д.) и все будет по-прежнему работать!

Это так здорово!

Однако, если вы проницательный пользователь, вы можете задаться вопросом: “Не повлияет ли унарный оператор на результат, возвращаемый из IIFE?

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

 

Мы добавляем эти скобки для лучшей читабельности.

Оператор With

Знаете ли вы, что в JavaScript есть оператор with, который создает новую область видимости “scope” и представляет свойства объекта “object” как локальные переменные выражения “statement”? Синтаксис оператора with выглядит следующим образом:

with (object)
   statement

// for multiple statements add a block

with (object) {
   statement
   statement
   ...
}

Пример использования оператора with:

 

🚩 Забавный факт

Использование оператора with не рекомендуется, так как он устарел. Он находится под полным запретом в строгом режиме (strict mode). Оказывается, with невозможно оптимизировать автоматически и нельзя определить куда ссылается переменная. То есть у данного оператора есть определенные проблемы с производительностью и безопасностью.

Function Constructor

Оператор function — не единственный способ объявить новую функцию. Существует еще один способ, использующий constructor (конструктор)Function() и оператор new.

 

Последний параметр constructor (конструктора) — это код функции в виде строки, а остальные параметры перед ним —  это аргументы функции.

🚩 Забавный факт

Constructor (конструктор) Function является прародительницей всех конструкторов в JavaScript. Даже сonstructor Object’s — это сonstructor Function. Следовательно, вызвав object.constructor.constructor...достаточное количество раз, в конечном итоге вернет сonstructor Function для любого объекта в JavaScript.

Свойства Function (Функции)

Мы все знаем, что Functions (Функции) — это объекты первого класса в JavaScript. Следовательно, никто не мешает нам добавить пользовательские свойства в Function. Тем не менее, этим редко кто пользуется.

Настраиваемые Functions (Функции)

Допустим, у нас есть функция с именем greet и мы хотим, чтобы она выводила разные приветствия (greeting message) в зависимости от региона (locale), в котором находится пользователь. Регион (locale) также должен быть настраиваемым. Для этого, как показано ниже, мы можем имплементировать (реализовать) функцию, используя свойства функций.

 

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

Еще один подобный пример. Допустим, вы хотите имплементировать (реализовать) Number Generator (генератор чисел), который генерирует ряд порядковых чисел. Обычно, для отслеживания последнего значения используется Class или IIFE со статической переменной counter. Таким способом мы ограничиваем доступ к counter, а также избегаем загрязнения глобального пространства дополнительными переменными.

Но что если мы захотим считывать или даже видоизменять counter, при этом не загрязняя глобальное пространство?

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

 

Свойства Arguments (Аргументов)

Я уверен, многие из вас знают об объекте arguments внутри функции. Это объект подобный массиву, доступный во всех функциях. Он содержит аргументы, переданные в функцию во время ее вызова. Также он обладает другими интересные свойствами:

  • arguments.callee: Относится к функции, исполняемой в текущий момент.
  • arguments.callee.caller: Относится к функции, которая вызвала текущую функцию.

 

Примечание: Хоть ES5 и запрещает использование callee & callerв строгом режиме, они по-прежнему встречаются во многих скомпилированных библиотеках. Именно поэтому стоит ознакомиться с ними поближе.

Теговые шаблонные литералы (Template Literals)

Если вы не из каменного века, то наверняка слышали о шаблонных литералах. Они появились в 6 редакции стандарта ECMAScript, то есть в ES6. Однако знаете ли вы о теговых (tagged) шаблонных литералах?

 

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

В следующем примере, наш пользовательский тег — highlight — интерпретирует значения шаблонного литерала, а также обернет интерпретированные значения в строку result, а конкретнее в элемент <mark> для выделения (highlighting).

 

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

Геттеры и Сеттеры

В большинстве случаев JavaScript объекты —  простые. Допустим, у нас есть объект user и мы пытаемся получить доступ к свойству age с помощью user.age. Мы либо получаем значение свойства age, если оно defined (определено), либо не получаем, если оно undefined (не определено). Все просто.

Но не обязательно должно быть так просто. JavaScript объекты обладают такой концепцией, как Getters и Setters (геттеры и сеттеры). Вместо того, чтобы непосредственно возвращать значение объекта, мы можем написать собственную функцию Getter, которая возвращает все, что мы захотим. То же самое касается установки значения объекта,то есть функции Setter.

Все это позволяет нам использовать такие концепции, как virtual fields(виртуальные поля), field validations (валидация форм), side-effects(побочные эффекты) при геттинге или сеттинге поля. 

 

Геттеры и сеттеры не являются чем-то новым в ES5, они уже были до этого. ES5 просто добавил удобный синтаксис к существующей функции.

Colors — популярная node.js библиотека, отличный пример использования геттеров.

Данная библиотека расширяет класс String и добавляет к нему несколько методов Getter. Colors дает возможность преобразовать любую строку в цветную версию, просто обратившись к свойствам строки, для удобного ведения логов.

Оператор запятая (comma)

В JavaScript есть оператор запятая (comma). Оператор запятая выполняет каждый из его операндов (слева направо) и возвращает значение последнего операнда.

// syntax
let result = expression1, expression2,... expressionN

Зачастую, данный оператор используется для передачи нескольких параметров в цикл for:

for (var a = 0, b = 10; a <= 10; a++, b--)

Иногда он помогает написать несколько операторов в одной строке:

function getNextValue() {
    return counter++, console.log(counter), counter
}

Также он помогает в написании коротких лямбда-функций:

const getSquare = x => (console.log (x), x * x)

Оператор + (плюс)

Хотите быстро преобразовать строку в число?

Просто поставьте перед строкой оператор +. Оператор плюс подходит для отрицательных, восьмеричных, шестнадцатеричных, экспоненциальных значений. Более того, он может преобразовать Dateили Moment.js объекты во временную метку (timestamp).

 

Оператор !! (Двойное отрицание)

Технически, это не отдельный JavaScript оператор. !! — это просто оператор ! (НЕ), используемый дважды.

Оператор !! используется для преобразования любого выражения в значение Boolean. 

Если выражение является истинным значением, оно возвращает true, в противном случае возвращается false.

 

Оператор ~ (тильда)

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

Что ж, для оператора Тильда (или Побитовое НЕ) существует сценарий для ежедневного использования.

Оказывается, при использовании с числом, оператор ~ эффективно выполняет ~N => -(N+1). Значение этого выражения равно “0” только тогда, когда N == -1.

Поместив ~ перед функцией indexOf(...), мы можем выполнить булевую проверку наличия элемента в String или в Array.

 

Примечание: В ES6 и ES7 добавили новый метод .includes() в String и Array соответственно. Безусловно, это более аккуратный способ, чтобы проверить, существует ли элемент в String или в Array.

Labelled statements

Вы можете применять label для обозначения циклов, чтобы затем при помощи breakили continue выходить из цикла или продолжать его работу с новой итерации.

 

Примечание: В отличие от некоторых других языков, в JavaScript нет оператора goto, вы можете использовать метки только с breakили continue.

 

Перевод статьи Viral ShahLittle known features of JavaScript