Шаблон раннего возврата (return early pattern) в JavaScript - это простой способ уменьшить число else-операторов в теле функции до нуля. Есть много причин, чтобы предпочесть этот шаблон использованию else-операторов.
Уменьшение общего количества кода на странице
Уменьшение длины строк кода упрощением логической сложности
Улучшение удобочитаемости кода
Суть шаблона раннего возврата (return early pattern) заключается в том, чтобы заменить необходимость дополнительных условий в функциях JavaScript, используя ключевое слово return в теле оператора if.
Создадим функцию, которая ведет себя по-разному при определенных условиях (примечание: это тривиальный и надуманный пример, просто чтобы получить представление о сути вопроса):
functionwillItBlend(someObject){varItWillBlend;if(someObject.blendable==='It will blend'){itWillBlend=true;}else{itWillBlend=false;}returnitWillBlend;}
Хотя данная функция кажется читаемой, добавим в нее еще одно условие для проверки того, что функция вызывается для работы с объектом вместо undefined:
functionwillItBlend(someObject){varitWillBlend;if(typeofsomeObject==='object'){if(someObject.blendable==='It will blend'){itWillBlend=true;}else{itWillBlend=false;}}else{itWillBlend=false;}returnitWillBlend;}
Эта функция понятной и ее имя является описательным, однако она представляется все-же излишне сложной. Можем ли мы использовать шаблон раннего возврата (return early pattern) для повышения удобочитаемости и уменьшения количества else-выражений?
Попробуем:
functionwillItBlend(someObject){if(typeofsomeObject!=='object'){returnfalse;}if(someObject.blendable!=='It will blend'){returnfalse;}returntrue;}
Используя шаблон раннего возврата (return early pattern), мы смогли удалить все ненужные else-инструкции и сделать функцию намного яснее и более краткой.
Бонус: одно условное выражение
Мы можем дополнительно переписать функцию для использования только одного оператора if.
Проверим:
functionwillItBlend(someObject){if(typeofsomeObject!=='object'||someObject.blendable!=='It will blend'){returnfalse;}returntrue;}
Метод call и apply достаточно древние - они оба из стандарта ES3. Суть создания и работы методов - заставить некоторую произвольную функцию работать на каком-то объекте. Точнее - использовать контекст этого объекта.
Чтобы было понятнее, начнем с примера. Есть функция, которая работает таким образом:
Что будет, если вызвать эту функцию таким образом?
getName()
Сложный вопрос, так как мы видим, что в теле функции используется ключевое слово this. Это - ссылка на текущий объект и на свойство name этого объекта. Что это за объект? Неизвестно. Все будет зависеть от того, где будет вызвана функция getName() на исполнение. Допустим, если вызвать функцию в консоли браузера, то парсер обратиться к глобальному объекту window и попробует найти у него свойство name. В итоге мы получим undefined, так как вряд ли у объекта window есть свойство name.
При помощи метода call можно “привязать” функцию getName() к любому объекту. Другими словами - привязать контекст функции getName() к контексту объекта. Как?
Что будет происходить здесь? В этом случае ключевое слово this (в теле функции getName) будет указывать на объект user1, у которого есть свойство name. Как результат - в константе result1 будет находиться значение Ivan.
Что будет? В этом случае функция getName будет ссылаться уже на объект user2! И в константе result2 уже будет значение свойства name объекта user2 - Joshua.
call - более сложный вариант
Рассмотрим более сложный случай - когда функция принимает аргумент(ы). Допустим, такая функция,
Что здесь произойдет? При каждом вызове функции promote() у нее будет разный контекст выполнения - объект junior, middle или senior. И обращаться функция promote() будет каждый раз к свойствам разных объектов - junior, middle или senior. Соответственно, результат тоже будет разным:
Видим, что аргументы передаются в виде массива, но результат будет тот же. Как часто упоминается в различных туториалах, это сделано для того, чтобы передать неограниченное и заранее неизвестное количество аргументов.
Метод bind
Этот метод похож на предыдущие два - call и apply. Однако, у него есть два отличия - этот метод появился в стандарте ES5; и второе отличие - этот метод позволяет выполнить отложенный вызов функции.
То есть - метод call или apply вызываются на исполнение сразу, и результат их работы мы получаем сразу. С методом bind немного иначе:
Что мы сдесь сделали? Мы вызвали функции promote() и передали ей контекст выполнения; результат - экземпляр функции promote() с уже встроенным контекстом выполнения; экземпляр помещен в константу resultAA, resultBB или resultCC. Другими словами - это готовые функции с контекстом.
Осталось вызвать любую из них и передать ей аргументы, которые она ожидает:
Видно, что у каждого созданного мною документа есть ключ _id со значением ObjectId(). Этого ключа я не указывал при создании документа.
Все правильно - этот ключ и его значение MongoDB генерирует автоматически и присваивает каждому создаваемому документу. Таким образом MongoDB делает все документы уникальными - нет ни одного документа с одинаковым _id.
Можно сделать вывод метода .find() более читабельным, если подключить к нему по цепочке еще один метод - .pretty():
Отличие метода save() от метода insert() заключается в том, что если при создании документа будет передан ключ _id уже существующего документа, то существующий документ будет перезаписан новым.
Стоит обратить внимание на ключ “_id” - этот ключ и значение ключа MongoDB автоматически генерирует для уникальной идентификации каждого документа в базе данных.
В базах данных MongoDB данные объединяются в коллекции - collection. В одной базе данных может быть от одной до многих collections.
Смысл collection - объединять однотипные данные. То есть данные, котороые можно объединить по какому-либо признаку.
Например, в базе данных animals может быть две collections - cats и dogs. В коллекции cats хранятся все данные, о которых можно сказать - “это данные по кошкам”. В коллекции dogs хранятся “все данные по собакам”.
Создание collection
В базе данных создать collection можно командой:
db.createCollection('NAME_COLLECTION')
Например, я создам две коллекции cats и dogs в базе данных animals. Для этого создам базу данных animals:
> use animals
switched to db animals
>
Создам коллекцию cats:
> db.createCollection('cats'){"ok" : 1 }
Создам коллекцию dogs:
> db.createCollection('dogs'){"ok" : 1 }
Посмотреть список существующих колекций базы данных можно командой:
show collections
Проверю, создались ли успешно коллеции cats и dogs в базе данных animals:
> show collections
cats
dogs
Переименование collection
Операция переименования collection в MongoDB выполняется командой:
db.collection.renameCollection('NEW_NAME')
Например, я создал коллекцию bird в базе данных animals:
В результате коллекция bird успешно переименована в birds.
Удаление collection
В MongoDB удаление коллекции выполняется командой:
db.COLLECTION_NAME.drop()
Например, я хочу удалить коллекцию birds из базы данных animals:
> db.birds.drop()true> show collections
cats
dogs
>
Коллекция birds успешно удалена из базы данных.
Создание collection - автоматический способ
В MongoDB имеется способ автоматического создания collection - путем добавления документа в новую коллецию при помощи метода insert.
Например, коллекции insects в базе данных animals не существует. В будущую коллекцию insects я добавлю документ cockroach и тем самым автоматически создам коллецию insects: