Function — Вопрос по JavaScript


Содержание

JavaScript: Функции

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

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

Объявление и вызов функции

Существует три способа объявления функции: Function Declaration, Function Expression и Named Function Expression.

Function Declaration (сокращённо FD) – это «классическое» объявление функции. В JavaScript функции объявляются с помощью литерала функции. Синтаксис объявления FD:

Литерал функции состоит из следующих четырёх частей:

  1. Ключевое слово function .
  2. Обязательный идентификатор, определяющий имя функции. В качестве имени функции обычно выбирают глагол, т. к. функция выполняет действие.
  3. Пара круглых скобок вокруг списка из нуля или более идентификаторов, разделяемых запятыми. Данные идентификаторы называются параметрами функции.
  4. Тело функции, состоящее из пары фигурных скобок, внутри которых располагаются инструкции. Тело функции может быть пустым, но фигурные скобки должны быть указаны всегда.

Встречая ключевое слово function интерпретатор создаёт функцию и затем присваивает ссылку на неё переменной с именем sayHi (переменная с данным именем создаётся интерпретатором автоматически).

Обратившись к переменной sayHi можно увидеть, что в качестве значения там находится функция (на самом деле ссылка на неё):

Function Expression (сокращённо FE) – это объявление функции, которое является частью какого-либо выражения (например присваивания). Синтаксис объявления FE:

Функцию FE иначе ещё называют » анонимной функцией «.

Named Function Expression (сокращённо NFE) – это объявление функции, которое является частью какого-либо выражения (например присваивания). Синтаксис объявления NFE:

Объявления FE и NFE обрабатываются интерпретатором точно так же, как и объявление FD: интерпретатор создаёт функцию и сохраняет ссылку на неё в переменной sayHi.

Программный код, расположенный в теле функции, выполняется не в момент объявления функции, а в момент её вызова. Для вызова функции используется оператор () (вызов функции):

Разница между представленными тремя объявлениями заключается в том, что функции, объявленные как FD, создаются интерпретатором до начала выполнения кода (на этапе анализа), поэтому их можно вызывать (в той области видимости где они объявлены) до объявления:

Функции, объявленные как FE или NFE, создаются в процессе выполнения кода, поэтому их можно вызывать только после того как они объявлены:

Функции, объявленные внутри блока, находятся в блочной области видимости:

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

Функция обратного вызова

Функция обратного вызова – это функция, которая передаётся в качестве аргумента другой функции для последующего её вызова.

Функции обратного вызова часто используются, в качестве обработчиков событий.

Ниже приведён пример функции, принимающей в качестве своего аргумента ссылку на другую функцию для её последующего вызова:

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

лабы по информатике, егэ

лабораторные работы и задачи по программированию и информатике, егэ по информатике

JavaScript урок 4. Javascript функции и объекты

Встроенные Javascript функции

В javascript достаточно много функций, встроенных в синтаксис языка. Рассмотрим одну из них.

eval(строка)

var y = 5; // значение у равно 5 var x = «if (y==5) y*2-3»; // значение х равно строке символов var rezult = eval(x); // rezult равно 7

Пользовательские Javascript функции

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

    Функция в роли процедуры. Если функция выполняет какие-либо действия и не возвращает значение:

Синтаксис объявления (создания) функции:

В javascript вызов функции в роли процедуры происходит следующим образом:

имя_функции (аргументы); // с аргументами имя_функции (); // без аргументов

В javaScript вызов функции, возвращающей значение, происходит, например, следующим образом:

var a = имя_функции (аргументы); alert(a); // 1-й способ var b = a + a; // 2-й способ

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

Продвинутая работа с функциями JavaScript

Учебник JavaScript

Практика

Работа с DOM

Практика

Некоторые продвинутые вещи

Рекомендованное ES6

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

Регулярки

Разное

Работа с канвасом

Практика

  • урок исключен (мало материала), по аяксу скоро будет отдельный учебник (много материала)
    Работа с
    AJAX в JavaScript
    Работа с
    AJAX + PHP

Контекст

Drag-and-Drop

  • Урок №
    Введение
    в ООП в стиле ES6
  • Урок №
    Основы
    работы с ООП
  • Урок №
    Наследование
    классов в JavaScript
    Продвинутая работа
    с классами на JavaScript
  • Урок №
    Применение
    ООП при работе с DOM
  • Урок №
    Практика
    по ООП в JavaScript
  • Тут скоро будут еще уроки
    по функциональному и прототипному
    стилю ООП.

Практика по ООП

Ваша задача: посмотрите, попробуйте повторить.

Практика

Promise ES6

Библиотека jQuery

Тк. jQuery устаревает, объявляю эти уроки не обязательными и выношу в конец учебника (так по уровню уроки середины учебника, если что). В перспективе переедет в отдельный учебник по jq.

В данном уроке мы разберем анонимные функции и замыкания на языке JavaScript.

Режим use strict

В JavaScript существует специальный режим, по которому код будет выполнятся по современному стандарту ES5, а не по более старому (это по умолчанию).

Этот режим включается директивой «use strict»; или ‘use strict’; и ставится в начале скрипта:

Строгий режим можно активировать только для кода функции:

Исходный код функции и результат

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

Функция как переменная

В JavaScript функции — это такие же переменные. К примеру, если у нас есть какая-то функция — мы можем записать ее в другую переменную — и эта функция станет доступна с другим именем:

Можно также создать безымянную функцию и записать ее в какую-то переменную:

Так как функция — это переменная, то невозможно существование переменной и функции с одинаковым именем. В следующем примере функция func будет затерта и вместо нее станет строка ‘hello’:

Функциональные выражения и объявление функций

Функцию можно объявить двумя способами: первый способ вы изучали в предыдущих уроках, а второй способ — это сделать безымянную функцию и записать ее в какую-либо переменную:

Первый способ называется Function Declaration (объявление функции), а второй — Function Expression (функциональное выражение):

По сути это одно и то же, но есть существенная разница: функции, объявленные как Function Declaration, создаются до выполнения кода. Поэтому их можно вызвать до объявления, например:

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

Функциональные выражения

Функциональные выражения достаточно удобная штука — можно, например, записать в переменную одну из функций, в зависимости от условия:

Особенности Function Declaration при use strict

Function Declaration при use strict видны только внутри блока, в котором объявлены. В данном случае функция func объявлена внутри ифа, но не будет видна снаружи:

Без use strict все будет нормально.

Передача функции по ссылке

Функции в JavaScript — это объекты. А объекты в JavaScript копируются по ссылке — это значит, что если у нас есть две переменные с одной и той же функцией — в них не лежит копия этой функции, а обе эти переменные ссылаются на одну и ту же функцию:

Анонимные функции

Функции, не имеющие имени, называются анонимными. Такие функции бывают полезны в тех случаях, когда имя функции нам без надобности и нет смысла тратить время на придумывание этого имени.

Пример: пусть у нас есть переменная elem, в которой лежит ссылка на какой-то элемент. Привяжем в качестве события onclick анонимную функцию:

Тоже самое при addEventListener:

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

Это имя будет доступно только внутри самой функции — и нигде извне.

Функция как параметр другой функции

Пусть у нас даны 2 функции:

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

Наша функция go запишет первую функцию в переменную func1, а вторую — в func2, затем просуммирует числа, возвращаемые этими функциями и выведет их на экран:

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

Рассмотрим еще пример: сейчас в функцию и go будем передавать параметром разные функции — и будем видеть разный результат:

А можем вообще использовать анонимную функцию, создаваемую в момент передачи параметра:

Функция в функции

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

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

Функция, возвращающая функцию

Функция может возвращать другую функцию, например так:

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

Чтобы увидеть результат работы внутренней функции — нужно вызвать внешнюю функции с двумя круглыми скобками:

Могут быть и такие вызовы функций: func()()() и func()()()() — и так далее до бесконечности. Для этого нужно, чтобы внутренняя функция тоже возвращала функцию, та — еще одну и так далее.

Область видимости переменных


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

То же самое будет, если у нас функция содержит внутри другую функцию — переменные внешней функции видны во внутренней:

Замыкания

Пусть у нас есть переменная num, определенная снаружи функции:

Если вызвать нашу функцию — то она сначала увеличит переменную num на единицу, а затем вернет новое значение num:

Если вызвать нашу функцию несколько раз — каждый раз она будет выводить на единицу больше, так как каждый вызов func приводит к увеличению внешней переменной num:

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

Обернем всю нашу конструкцию в функцию (назовем ее createCounter), а функцию func, которая у нас была ранее, сделаем анонимной и сделаем так, чтобы новая функция createCounter возвращала эту анонимную функцию:

Рассмотрим подробнее, что тут происходит: переменная num является локальной внутри функции createCounter, но при этом она доступна в анонимной функции (это мы видели в предыдущих примерах). В строчке var counter = createCounter() анонимная функция запишется в переменную counter. Получится, что у нас далее есть функция counter, внутри которой доступна переменная num из createCounter.

Давайте убедимся в этом:

Давайте теперь запустим функцию counter несколько раз — мы увидим, что каждый раз она будет выводить на единицу больше:

Еще раз: преимуществом такого подхода является то, что переменная num не видна снаружи createCounter и ее никто не сможет случайно затереть. Снаружи она не видна, но доступ к ней есть — через функцию counter, но только через нее.

Такая штука называется замыкание. Замыкание — это функция со всеми доступными внешними переменными (типа num в нашем случае). Эти переменные называются лексическим окружением функции.

Давайте вернемся назад к счетчику — осталось самое интересное: если createCounter вызвать несколько раз, записав результат в разные переменные — каждая из них станет независимым счетчиком.

В следующем примере у нас есть 2 функции: counter1 и counter2 — и они работают совершенно не мешая друг другу (получается, что у каждой из них своя переменная num):

Вызов функции на месте

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

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

Для вызова функции на месте хотелось бы сделать что-то в таком роде:

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

Так тоже будет работать:

Но более принято брать такие функции в круглые скобки, вот так:

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

Иногда во избежания ошибок в начале ставится точка с запятой (ошибки могут возникнуть при сжатии файла минимизатором):

Функции JavaScript

JavaScript function позволяют организовать скрипты и упрощают повторное использование кода. Вместо того чтобы создавать длинные фрагменты кода, разбросанные по всей HTML-странице , скрипты организуются в логические группы.

Объявление и вызов функции JavaScript

Синтаксис функции JavaScript выглядит следующим образом:

Имя определяет, как мы будем называть функцию при ее вызове. Аргументы задают значения, которые передаются функции для обработки. Раздел операторы представляет собой тело функции, которая выполняет обработку. Необязательный оператор return позволяет вернуть значение.

В следующем примере показана функция, определяемая в разделе HTML-страницы и вызываемая в разделе :

Передача аргументов в функцию

В приведенном выше примере ( script type text JavaScript function ) функции не передается никакие аргументы. Обычно функция предназначена для выполнения каких-либо действий с несколькими аргументами:

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

Возврат значения из функции

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

В приведенном выше примере мы передаем в функцию addValues значения 10 и 20 . Функция addValues складывает эти два значения и возвращает результат. Оператор return присваивает результат переменной result, которая затем используется для создания строки, выводимой на HTML-странице .

Вызов JavaScript function может быть выполнен в разных местах. Например, не обязательно присваивать результат в качестве значения переменной. Можно использовать его непосредственно в качестве аргумента при вызове document.write .

Важно отметить, что функция может возвращать только одно значение:

Где размещать объявления функций

Есть два места, в которых рекомендуется размещать объявления JavaScript function return: внутри раздела HTML-документа или во внешнем файле .js . Наиболее предпочтительным местом считается второй вариант, так как он обеспечивает наибольшую гибкость.

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

Данная публикация представляет собой перевод статьи « Understanding JavaScript Functions » , подготовленной дружной командой проекта Интернет-технологии.ру

Функции в JavaScript

Зачастую нам нужно повторять одни и те же действия в разных частях кода JavaScript. Например, иногда требуется передать сообщение при входе пользователя на сайт, при выходе и в других случаях. Чтобы не повторять тот же код множество раз, используют функции (functions). По сути, функции — это основные «строительные кирпичики» программы на JavaScript.

Примеры встроенных функций: • prompt(message, default); • alert(message); • confirm(question).

Однако в JavaScript можно создавать и свои функции.

Объявление функций в JS

Рассмотрим пример создания function для показа сообщений showMessage() :

В вышеприведённом примере ключевое слово — function, которое идёт в самом начале. Потом прописывается имя функции, затем параметры (в скобках), далее — тело функции (код, выполняемый при вызове).

Объявленная таким образом функция будет доступна по имени:

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

Локальные переменные функции

В функцию могут входить и локальные переменные (объявляются через var). Они видны только внутри функции:

Помните, что блоки while, switch, for, if/else, do..while никак не влияют на зону видимости переменных, то есть при объявлении переменных в данных блоках они будут видны во всей функции. Пример:

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

Внешние переменные функции

Функция позволяет вызвать и внешнюю переменную, например:

Доступ возможен на чтение и запись. Но раз переменная внешняя, изменения видны и снаружи функции:

Однако если бы мы внутри функции в строке (1) объявили свою локальную переменную var userName , все обращения задействовали бы её, то есть внешняя переменная не изменилась бы.

Параметры, которые можно вызвать функцией

При вызове function ей можно отправить данные для обработки. Например, нижеследующий код выведет 2 сообщения:

Помните, что когда код будет передан, параметры скопируются в локальные переменные. Также функцию можно вызвать практически с любым количеством аргументов, а если при вызове параметр не будет передан, он считается равным undefined. К примеру, функцию отображения сообщений showMessage(from, text) можно без проблем вызвать, используя один аргумент:

Выбор имени function

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

Функцию, которая что-то показывает, называют show (это лучший вариант для имени):

Запуск function, которая что-то получает, называют get, вычисляет — calc и т. д.

Примеры, каким именем можно назвать функцию:

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

Остаётся запомнить, что вне зависимости от метода названия, одна функция — это одно действие. Если функция подразумевает поддействия, желательно выделить их в отдельные функции.

Функция jQuery() в JavaScript

Говоря о применении функций в JS, нельзя не упомянуть jQuery — известнейшую библиотеку языка программирования JavaScript, благодаря которой осуществляется взаимодействие HTML и JavaScript. Работа с ней начинается с вызова основной функции jQuery() либо $() . Данная функция (function) может выполнять разные действия, что зависит от того, какое значение передать в качестве параметров аргумента.

Какие задачи решаются с помощью этой функции?

В зависимости от параметров возможно выполнение следующих действий: — поиск на основе селектора элементов в DOM-дереве и их возвращение в виде объекта; — оборачивание DOM-элементов, указанных в качестве параметров аргумента, в объект jQuery; — создание DOM-элементов в памяти с помощью HTML-строки, переданной в качестве аргумента функции; — выполнение указанной функции после того, как DOM-дерево окончательно загрузится браузером; — оборачивание простого JavaScript-объекта, содержащего ноль либо больше пар «ключ-значение» в объект jQuery; — клонирование объекта (актуально, если его нужно передать в качестве параметров функции).

Если параметры не указывать, то function возвращает пустой jQuery-объект.

Для примера рассмотрим функцию jQuery(html,attributes) и функцию jQuery(html[,ownerDocument]) .

Функция jQuery(html,attributes)

Function служит для создания DOM-элемента с параметрами. Необходимый элемент указывается в первом аргументе с помощью HTML-строки. Атрибуты к нему указываются во втором аргументе с помощью объекта JavaScript (PlainObject).

Данный способ вызова функции имеет два параметра: • html — обязательный параметр типа htmlString, содержит DOM-элемент; • attributes — необязательный параметр типа PlainObject. Это объект, содержащий атрибуты, методы и события, которые нужно передать создаваемому элементу.

Примечание: необходимо, чтобы HTML-строка начиналась с $.parseHTML() ; — после обработки запускается процесс создания DOM-узлов (применяется браузерный механизм .innerHTML ); — в конечном итоге функция возвращает объект jQuery, включающий созданные DOM-узлы.

Если пользоваться только одним параметром, элементы создаются для текущего документа. Если хотите создать элементы для другого документа, нужно передавать и 1-й, и 2-й параметры.

Ссылки в JS

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

  • Самый простой метод, позволяющий осуществлять вызов — вывод alert в ссылке. Пример такой ссылки (ссылку можно запустить без проблем из любого браузера):
  • Второй метод вызова ссылки имеет более сложную конструкцию. В этом случае ссылку можно сделать с помощью функции document.write(). А оформить такую ссылку можно следующим образом:
  • В качестве третьего метода продемонстрируем ещё более усложнённый вариант. Ссылка и её вызов осуществляются с помощью переменных, т. к. сама ссылка и её текст выведены в отдельные переменные:

Кроме того, можно вызывать ссылку через таблицу, div, ячейку таблицы и путём использования другого метода. Собственно говоря, использование этих методов для передачи ссылок — довольно странное занятие, если вспомнить, что у нас есть простые, эффективные и всем понятные решения с html и php.

Как создать очередность выполнения функций в js?

Дорогие друзья, товарищи, коллеги. Есть вопрос по JS, в данное время нет идей, как можно реализовать + опыт пока не очень (но я стараюсь, честно).

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

Суть такова: эти функции выводят в элемент DOM вопросы с вариантами ответов. На данном этапе у меня получается так, что они разом выводятся в этот div и всё. А хотелось бы, чтобы следующая функция не выводилась до тех пор, пока текущая не получит ответ от пользователя. Т.е. чтобы основной поток находился в режиме ожидания до взаимодействия.

Оговорюсь сразу — использовать prompt и confirm не является решением.

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

Сейчас функций мало, массив небольшой. А если их будет большее количество (20, например) — могут возникнуть определенные сложности + если мы будем вызывать эту функцию из массива, то после неё будет исполняться следующая, что совершенно не приемлемо.

  • Вопрос задан 03 апр.
  • 1202 просмотра

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

Вам нужно, чтобы по событию вызывалась функция, в которой будут в определенном порядке вызываться три остальные? Причем этих остальных функций может быть N-ое количество и вызываться они должны в строгом порядке и только друг за дружкой?

Или Вам нужно показывать модальные окна, после завершения обработки каждого из которых будет вызываться следующее?

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

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

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

Вот пример с комментариями.

Но сразу хочу сказать, что это просто один из вариантов решения. Всё это конечно же можно сделать на промисах.

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

JavaScript Определения функций

Функции JavaScript определяются с помощью ключевое слово Function .

Можно использовать объявление функции или выражениефункции.

Объявления функций

Ранее в этом учебнике было показано, что функции объявляются со следующим синтаксисом:

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

Пример


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

Выражения функций

Функция JavaScript также может быть определена с помощью выражения.

Выражение функции может храниться в переменной:

Пример

После того как выражение функции Сохранено в переменной, переменная может быть использована в качестве функции:

Пример

Функция выше на самом деле является анонимной функцией (функция без имени).

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

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

Конструктор Function()

Как вы видели в предыдущих примерах, функции JavaScript определяются с помощью ключевого слова Function.

Функции можно также определить с помощью встроенного конструктора функции JavaScript, называемого Function ().

Пример

var myFunction = new Function(«a», «b», «return a * b»);

var x = myFunction(4, 3);

На самом деле не нужно использовать конструктор функций. Приведенный выше пример аналогичен написанию:

Пример

var myFunction = function (a, b) ;

var x = myFunction(4, 3);

Большую часть времени, вы можете избежать использования нового ключевого слова в JavaScript.

Функция подъема

Ранее в этом учебнике, вы узнали о «подъема».

Подъем — это поведение по умолчанию JavaScript при перемещении объявлений в верхнюю часть текущей области.

Подъем применяется к объявлениям переменных и объявлениям функций.

По этой причине функции JavaScript могут быть вызваны до их объявления:

function myFunction(y) <
return y * y;
>

Функции, определенные с помощью выражения, не поддаются подъему.

Функции, ссылающиеся на себя

Выражения функции могут быть сделаны «Self-вызов».

Само-вызывающее выражение вызывается (запускается) автоматически, без вызова.

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

Нельзя самостоятельно вызвать объявление функции.

Вы должны добавить круглые скобки вокруг функции, чтобы указать, что это выражение функции:

Пример

Функция, приведенная выше, на самом деле является анонимной функцией самовызова (функция без имени).

Функции могут использоваться в качестве значений

Функции JavaScript могут использоваться в качестве значений:

Пример

function myFunction(a, b) <
return a * b;
>

var x = myFunction(4, 3);

Функции JavaScript можно использовать в выражениях:

Пример

function myFunction(a, b) <
return a * b;
>

var x = myFunction(4, 3) * 2;

Функции являются объектами

Оператор typeof в JavaScript возвращает функцию «Function» для функций.

Но функции JavaScript лучше всего описать как объекты.

Функции JavaScript имеют как Свойства , так и методов.

Свойство Arguments. Length возвращает число аргументов, полученных при вызове функции:

Пример

Метод ToString () возвращает функцию в виде строки:

Пример

function myFunction(a, b) <
return a * b;
>

var txt = myFunction.toString();

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

Как работает JavaScript

Почему понимание основ бесценно

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

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

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

Как это работает?

Компьютеры не понимают JavaScript – браузеры понимают.

Помимо обработки сетевых запросов, прослушивания кликов мыши и интерпретации HTML и CSS для рисования пикселей на экране, в браузер встроен движок JavaScript.

Движок JavaScript – это программа, написанная, скажем, на C ++, которая обрабатывает весь код JavaScript, символ за символом, и «превращает» его в нечто, что ЦП компьютера может понять и выполнить – то есть в машинный код.

Это происходит синхронно, то есть по одной строке за раз и по порядку.

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

Таким образом, движок делают всю эту работу за разработчиков JavaScript, иначе веб-разработка была бы намного сложнее, менее популярной, и у нас не было бы таких вещей, как Medium (оригинальная статья размещена на Medium), где мы могли бы писать статьи, подобные этой (и я бы сейчас спал) ,

Движки JavaScript отличаются по типу выполнения. Он может пройти по каждой строке JavaScript и выполнять их по строчно (см. Интерпретатор), или он может быть умнее и обнаруживать такие вещи, как функции, которые часто вызываются и всегда дают один и тот же результат. Затем он может скомпилировать их в машинный код только один раз, чтобы в следующий раз, когда он встретит его, он выполнял уже скомпилированный код, что намного быстрее (см. Компиляция Just-in-time). Или он может заранее скомпилировать весь код в машинный код (см. Compiler).

Сейчас самый распространенный V8 – это такой движок JavaScript, который Google был создан в 2008 году. В 2009 году у парня по имени Райан Даль появилась идея использовать V8 для создания Node.js, среды выполнения для JavaScript вне браузера, что означало, что этот язык может также использоваться для серверных приложений.

Контекст выполнения функции

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

Эти правила определяются организацией по стандартизации Ecma International, и вместе они образуют документ спецификации языка (вы можете найти последнюю версию здесь).

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

Что если код содержит недопустимое присваивание или он пытается получить доступ к переменной, которая, согласно спецификации языка, не должна быть доступна из этой конкретной части кода?

Цукерберг рекомендует:  Продакт-менеджер

Каждый раз, когда вызывается функция, ей нужно все это понять. Это достигается путем создания оболочки, называемой контекстом выполнения (execution contex).

Чтобы быть более конкретным и избежать путаницы в будущем, я буду называть этот контекст выполнения функции (function execution context), потому что он создается каждый раз, когда вызывается функция. Не пугайтесь этого термина и не думайте о нем слишком много сейчас, он будет подробно описано позже.

Просто помните, что он определяет такие вещи, как: «Какие переменные доступны в этой конкретной функции, какое значение this внутри нее, какие переменные и функции объявлены внутри нее?»

Глобальный контекст выполнения

Но не весь код JavaScript находится внутри функций.

Также код может быть вне любой функции на глобальном уровне, поэтому одна из самых первых вещей, которую делает движок JavaScript, – это создание глобального контекста выполнения (global execution context).

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

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

Глобальный контекст выполнения создает две вещи, которые специфичны для него, даже если нет кода для выполнения:

  • Объект window, когда JavaScript запускается внутри браузера. Когда он запускается вне его, как в случае с Node.js, он будет чем-то вроде global. Для простоты я буду использовать window в этой статье.
  • Специальную переменная которая называется this.

В глобальном контексте выполнения, и только там, this фактически равняется объекту window. Это в основном ссылка на window.

Другое тонкое различие между глобальным контекстом выполнения и контекстом выполнения функции заключается в том, что любые переменные или функции, объявленные на глобальном уровне (вне какой-либо функции), автоматически присоединяются в качестве свойств к объекту window и неявно к специальной переменной this.

Хотя функции также имеют специальную переменную this, этого не происходит в контексте выполнения функции.

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

Все встроенные в JavaScript переменные и функции присоединяются к глобальному объекту window: setTimeout(), localStorage, scrollTo(), Math, fetch() и т. д. Именно поэтому они доступны в любом месте кода.

Стек исполнения (Execution Stack)

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

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

Посмотрите на следующий пример:

Когда происходит вызов функции a(), создается контекст выполнения функции, как описано выше, и выполняется код внутри функции.

Когда выполнение кода завершено (оператор return или скобка > ), контекст выполнения функции для функции a() уничтожается.

Затем происходит вызов b(), и тот же процесс повторяется для функции b().

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

В этом случае создается контекст выполнения функции для a(), и прямо в середине выполнения a() встречается вызов b(). Абсолютно новый контекст выполнения функции создается и для b(), но без разрушения контекста выполнения a(), так как его код еще не полностью выполнился.

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

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

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

Этот стек называется стеком выполнения (execution stack), представленным на рисунке ниже.

JavaScript execution stack

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

Очередь событий (Event Queue)

Помните, когда я говорил, что движок JavaScript – это всего лишь один компонент браузера, наряду с движком рендеринга или сетевым уровнем?

Эти компоненты имеют встроенные хуки (Hooks), с помощью которых ядро взаимодействует для инициирования сетевых запросов, рисования пикселей на экране или прослушивания щелчков мыши.

Когда вы используете что-то вроде fetch в JavaScript для выполнения HTTP-запроса, механизм фактически передает это на сетевой уровень. Всякий раз, когда приходит ответ на запрос, сетевой уровень передает его обратно движку JavaScript.

Но это может занять несколько секунд, что делает движок JavaScript во время выполнения запроса?

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

Ничего из вышеперечисленного, хотя первое может быть достигнуто с помощью await.

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

Чтобы понять, как это на самом деле работает, давайте рассмотрим функции a() и b(), которые мы рассматривали ранее, но добавим обработчик кликов мыши и обработчик HTTP-запросов.

Любое событие, полученное движком JavaScript от других компонентов браузера, например клик мыши или ответ по сети, не будет обработано немедленно.


Движок JavaScript может быть занят выполнением кода в этот момент, поэтому вместо этого он поместит событие в очередь, называемую очередью событий (event queue).

JavaScript Event Queue

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

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

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

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

Поскольку этот обработчик является функцией JavaScript, он будет обрабатываться так же, как обрабатывались a() и b(), что означает, что создается контекст выполнения функции и помещается в стек выполнения.

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

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

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

Вы можете легко увидеть это в действии, скопировав следующий код в консоль браузера:

Цикл while просто загрузит движок на пять секунд. Начните щелкать в любом месте документа в течение этих пяти секунд, и вы увидите, что на консоли ничего не отобразиться.

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

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

На самом деле, то же самое происходит с setTimeout()setInterval()). Обработчик, который вы предоставите для setTimeout(), фактически помещается в очередь событий. Это означает, что если вы установите тайм-аут на 0, но в стеке выполнения будет код, обработчик для setTimeout() будет вызван только тогда, когда стек будет пустым, что может произойти через множество миллисекунд.

Это одна из причин, почему setTimeout() и setInterval() не совсем точны. Скопируйте и вставьте следующий текст в консоль браузера, если вы не поверите мне на слово.

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

Этапы контекста выполнения функции

Теперь, когда мы знакомы с жизненным циклом выполнения JavaScript-программы, давайте еще немного углубимся в то, как именно создается контекст выполнения функции.

Это происходит в два этапа: этап создания и этап выполнения.

Этап создания «настраивает» так, что код может быть выполнен, а этап выполнения фактически выполняет его.

На этапе создания происходят две вещи, которые очень важны:

  • определяется область действия (scope).
  • определяется значение this (я предполагаю, что вы уже знакомы с ключевым словом this в JavaScript).

Каждый из них подробно описан в следующих двух соответствующих разделах.

Scope и Scope Chain

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

При достижении console.log(foo), движок JavaScript сначала проверит, есть ли переменная foo в области контекста выполнения b(). Поскольку там ее нет, он перейдет в «родительский» контекст выполнения, который является контекстом выполнения a(), просто потому, что b() объявлен внутри a(). В области видимости этого контекста выполнения он найдет foo и выведет ее значение.

Если мы определим b() вне a(), вот так:

Будет сгенерировано ReferenceError, хотя единственное различие между ними заключается в месте, где объявлено b().

«Родительская» область действия b() теперь является глобальной областью контекста выполнения, поскольку она объявляется на глобальном уровне вне какой-либо функции, и там нет переменной foo.

Я могу понять, почему это может сбивать с толку, потому что, если вы посмотрите на стек выполнения, это выглядит так:

JavaScript execution stack

Таким образом, легко предположить, что «родительский» контекст выполнения является следующим в стеке, ниже текущего. Однако это не так.

В первом примере контекст выполнения a() действительно является «родительским» контекстом выполнения b(). Не потому, что a() является следующим элементом в стеке выполнения, чуть ниже b(), а просто потому, что b() объявлен внутри a().

Во втором примере стек выполнения выглядит так же, но на этот раз «родительский» контекст выполнения b() является глобальным контекстом выполнения, потому что b() объявлен на глобальном уровне.

Просто помните: не важно, где вызывается функция, важно, где она объявлена.

Но что произойдет, если она не сможет найти переменную в области «родительского» контекста выполнения?

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

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

Это называется цепочкой областей действия (scope chain), и это именно то, что происходит в следующем примере:

Сначала он пытается найти foo в области контекста выполнения c(), затем b(), а затем, в конце концов, a(), где он его найдет.

Примечание: Помните, что движок переходит только от c() к b() и a(), потому что они объявлены внутри другого, а не потому, что их соответствующие контексты выполнения располагаются поверх другого в стеке выполнения.

Если они не будут объявлены внутри другого, тогда «родительский» контекст выполнения будет другим, как объяснено выше.

Однако, если бы внутри c() или b() была другая переменная foo, ее значение было бы выведено на консоль, потому что движок прекратит «поиск» «родительских» контекстов выполнения, как только найдет переменную.

То же самое относится и к функциям, а не только к переменным, и то же относится к глобальным переменным.

Примечание. Несмотря на то, что в приведенных выше примерах я использовал только синтаксис объявления функции, область действия и цепочка областей действия работают точно так же и для стрелочных функций, которые были представлены в ES2015 (также называемой ES6).

Замыкание (Closure)

Замыкание обеспечивает доступ к области действия внешней функции из внутренней функции.

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

Это именно то, что происходит в приведенном выше примере. b() объявлена внутри a(), поэтому она может получить доступ к переменной name из области видимости a() через цепочку областей видимости.

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

Переменная c является просто ссылкой на внутреннюю функцию b(), поэтому последняя строка кода фактически вызывает внутреннюю функцию b().

Вы можете прочитать больше о том, как вы можете использовать замыкания в статье на Medium, написанной Эриком Эллиоттом.

Значение this

Следующее, что определяется на этапе создания контекста выполнения, это значение this.

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

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

Прежде всего, это зависит от того, как объявлена функция. С помощью объявления функций:

Или стрелочной функций:

Функция стрелок

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

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

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

Мы можем увидеть это в двух примерах ниже.

Первый из них будет записывать true, а второй – false, хотя myArrowFunction вызывается в одном и том же месте в обоих случаях. Единственное различие между ними заключается в том, где была объявлена стрелочная функция.

Поскольку значение this внутри myArrowFunction является лексическим, в первом примере это будет window, поскольку оно объявлено на глобальном уровне вне какой-либо функции или класса.

Во втором примере значение this внутри myArrowFunction будет значением this внутренней функции, которая его оборачивает.

Я расскажу о том, что именно это значение, позже в этом разделе, но пока достаточно заметить, что это не window, как в первом примере.

Помните: для функций со стрелками значение this определяется в зависимости от того, где объявлена стрелочная функция, а не где и как она вызывается.

Объявления функций

В этом случае все не так просто, и это как раз причина (или, по крайней мере, одна из них), почему стрелочные функции были введены в ES2015.

Помимо разницы в синтаксисе между функциями стрелок (const a = () => <…>) и объявлениями функций (function a () <…>), значение this является основным отличием между ними.

В отличие от стрелочных функций, значение this при обычном объявление функций не определяется лексически в зависимости от того, где объявлена функция. Оно определяется в зависимости от того, как вызывается функция. И есть несколько способов вызвать функцию:

  • Простой вызов: myFunction()
  • Вызов метода объекта: myObject.myFunction()
  • Вызов конструктора: new myFunction()
  • Вызов обработчика событий DOM: document.addEventListener(‘click’, myFunction)

Значение this внутри myFunction() определяется по-разному для каждого из этих типов вызовов, независимо от того, где объявлена функция myFunction(), поэтому давайте рассмотрим их один за другим и посмотрим, как это работает.

Простой вызов

Простой вызов – это просто вызов функции, как в примере выше: само имя функции, без каких-либо предшествующих символов, за которым следует скобки () (конечно, с любыми дополнительными аргументами внутри).

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

Но помните, это верно только для простого вызова; за именем функции следует ().

Примечание. Поскольку значение this в простом вызове функции на самом деле является ссылкой на объект глобального window, использование this внутри функций, которые должны вызываться простым вызовом, считается плохой практикой. Это потому, что любые свойства, прикрепленные к this внутри функции, на самом деле присоединяются к объекту window и становятся глобальными переменными, что является плохой практикой.

Вот почему в строгом режиме (strict mode) значение this внутри любой функции, вызываемой простым вызовом undefined, и в приведенном выше примере будет выведено значение false.

Вызов метода объекта

Когда свойство объекта объявлена как функция в качестве значения, оно считается методом этого объекта, отсюда и термин вызов метода (method invocation).

Когда используется этот тип вызова, значение this внутри функции будет просто указывать на объект, для которого вызывается метод, который в примере выше является myObject .

Примечание. Если бы использовался синтаксис стрелочных функций, вместо объявления функции, значением this функции внутри был бы объект window.

Это потому, что его родительский контекст выполнения был бы глобальным контекстом выполнения. Тот факт, что он объявлен внутри объекта, ничего не меняет.

Вызов конструктора

Другой способ вызвать функцию – это добавить к вызову ключевое слово new, как в примере ниже.

Когда функция вызывается таким образом, функция возвращает новый объект (даже если у него нет оператора return), и значение this внутри функции будет указывать на этот вновь созданный объект.

Объяснение немного упрощено (подробнее тут в MDN).

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

Примечание. Стрелочные функции нельзя использовать в качестве конструктора.

Вызов обработчика событий DOM

Когда функция вызывается как обработчик события DOM, значением this внутри функции будет элемент DOM, в который было помещено событие.

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

Вызов с пользовательским значением this

Значение this внутри функции может быть явно установлено, вызывая функцию с помощью bind(), call() или apply() из Function.prototype.

В приведенном выше примере показано, как работает каждый из них.

call() и apply() очень похожи, единственное отличие состоит в том, что с apply() аргументы функции передаются в виде массива.

Хотя call() и apply() фактически вызывают функцию со значением this с тем что вы передаете в качестве первого аргумента, bind() не вызывает функцию.

Вместо этого он возвращает новую функцию, которая в точности соответствует функции, с которой была использована bind(), но со значением this равным тому, что вы передаете в качестве аргумента для bind().

Вот почему вы видите (5, 6) после a.bind (obj), чтобы фактически означает вызов функции, возвращаемую bind().

В случае bind() значение this внутри возвращаемой функции постоянно связано с тем, что вы передаете в качестве значения this (отсюда и имя bind()).

Независимо от того, какой тип вызова используется, значение this внутри возвращаемой функции всегда будет тем, которое было предоставлено в качестве аргумента. Его можно изменить только снова с помощью call(), bind() или apply().

Но есть и исключение из правил, и это исключение является вызовом конструктора. При вызове функции таким способом, помещая ключевое слово new перед вызовом, значением this внутри функции всегда будет объект, возвращаемый вызовом, даже если новой функции было дано другое this с помощью bind().

Вы можете проверить это в следующем примере:

Вот пример того, как вы будете использовать bind() для управления значением this для обработчика события click, который мы обсуждали ранее:

Примечание: bind(), call() и apply() не могут быть использованы для передачи пользовательского значения this стрелочным функциям.

Примечание о стрелочных функциях

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

Небольшое изменение в том, как вызывается функция, изменит значение this внутри нее. Это может вызвать цепную реакцию, и поэтому важно знать эти правила и то, как они могут повлиять на ваш код.

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

Поднятие (Hoisting)

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


На этом первом этапе (этапе создания) эти переменные получают специальное значение undefined, независимо от того, какое фактическое значение им назначено в коде.

Только на втором этапе (этапе исполнения) им присваивается фактическое значение, и это происходит только при достижении строки назначения.

Вот почему следующий код JavaScript выведет undefined:

На этапе создания переменная a идентифицируется, и ей присваивается специальное значение undefined.

Затем, на этапе выполнения, достигается строка, которая выводит на консоль a значение undefined, так как она было установлено в качестве значения на предыдущем шаге.

Когда будет достигнута строка, где ей назначено значение 1, значение a изменится на 1, но значение undefined уже было выведено в консоли.

Этот эффект называется подъемом (hoisting), как если бы все объявления переменных были подняты в верхнюю часть кода. Как видите, это не совсем то, что происходит, но именно этот термин, используется для его описания.

Примечание: это также происходит со стрелочными функциями, но не с обычными функциями. На этапе создания функциям не назначается специальное значение undefined, а вместо этого все тело функции помещается в память. Вот почему функция может быть вызвана еще до ее объявления, как в примере ниже, и она будет работать.

Примечание. При попытке получить доступ к переменной, которая вообще не была определена, выдается ReferenceError: x is not defined. Таким образом, существует разница между «undefined» и «not defined», что может немного сбивать с толку.

Заключение

Я помню, как читал статьи о поднятие, области видимости, замыканиях и т. д., И все они имели смысл, когда я их читал, но когда я всегда сталкивался с каким-то странным поведением JavaScript, я просто не мог это объяснить Проблема заключалась в том, что я всегда читал о каждой концепции по отдельности, по одной за раз. Поэтому я попытался дать общую картину как работает движок JavaScript. Как создаются контексты выполнения и помещаются в стек выполнения, как работает очередь событий, как определяется this и область действия и т. д. После этого мне стало проще обнаруживать потенциальные проблемы, быстрее искать источники ошибок и я стал чувствовать себя намного увереннее в программирование в целом.

Я надеюсь, что эта статья сделает то же самое для вас!

Function — Вопрос по JavaScript

Список (продвинутых) вопросов по JavaScript

Я ежедневно публикую вопросы по JavaScript с вариантами ответов в своем Instagram, которые дублируются в этом репозитории.

От базового до продвинутого: проверьте, насколько хорошо вы знаете JavaScript, немного освежите свои знания или подготовьтесь к собеседованию! �� �� Я обновляю репозиторий еженедельно новыми вопросами. Последнее обновление: 9 октября.

Ответы находятся в свернутой секции ниже вопросов. Просто нажми на «Ответ», чтобы развернуть. Удачи! ❤️

Хотите получать электронную почту всякий раз, когда я добавляю новые вопросы?
✨ ✉Подпишитесь на обновления✉ ✨

Список доступных переводов:

1. Что будет в консоли?

  • A: Lydia и undefined
  • B: Lydia и ReferenceError
  • C: ReferenceError и 21
  • D: undefined и ReferenceError

Ответ

Внутри функции мы сперва определяем переменную name с помощью ключевого слова var . Это означает, что переменная будет поднята (область памяти под переменную будет выделена во время фазы создания) со значением undefined по умолчанию, до тех пора пока исполнение кода не дойдет до строчки, где определяется переменная. Мы еще не определили значение name когда пытаемся вывести её в консоль, поэтому в консоли будет undefined .

Переменные, определенные с помощью let (и const ), также поднимаются, но в отличие от var , не инициализируются. Доступ к ним не возможен до тех пор, пока не выполнится строка их определения (инициализации). Это называется «временная мертвая зона». Когда мы пытаемся обратиться к переменным до того момента как они определены, JavaScript выбрасывает исключение ReferenceError .

2. Что будет в консоли?

  • A: 0 1 2 и 0 1 2
  • B: 0 1 2 и 3 3 3
  • C: 3 3 3 и 0 1 2

Ответ

Из-за очереди событий в JavaScript, функция setTimeout вызывается после того как цикл будет завершен. Так как переменная i в первом цикле была определена с помощью var , она будет глобальной. В цикле мы каждый раз увеличиваем значение i на 1 , используя унарный оператор ++ . К моменту выполнения функции setTimeout значение i будет равно 3 в первом примере.

Во втором цикле переменная i определена с помощью let . Такие переменные (а также const ) имеют блочную область видимости (блок это что угодно между < >). С каждой итерацией i будет иметь новое значение, и каждое значение будет замкнуто в своей области видимости внутри цикла.

3. Что будет в консоли?

  • A: 20 и 62.83185307179586
  • B: 20 и NaN
  • C: 20 и 63
  • D: NaN и 63

Ответ

Заметь, что diameter это обычная функция, в то время как perimeter это стрелочная функция.

У стрелочных функций значение this указывает на окружающую область видимости, в отличие от обычных функций! Это значит, что при вызове perimeter значение this у этой функции указывает не на объект shape , а на внешнюю область видимости (например, window).

У этого объекта нет ключа radius , поэтому возвращается undefined .

4. Что будет в консоли?

  • A: 1 и false
  • B: false и NaN
  • C: false и false

Ответ

Унарный плюс приводит операнд к числу. true это 1 , а false это 0 .

Строка ‘Lydia’ это «истинное» значение. На самом деле мы спрашиваем «является ли это истинное значение ложным»? Ответ: false .

5. Что НЕ является валидным?

  • A: mouse.bird.size
  • B: mouse[bird.size]
  • C: mouse[bird[«size»]]
  • D: Все варианты валидны

Ответ

В JavaScript все ключи объекта являются строками (кроме Symbol). И хотя мы не набираем их как строки, они всегда преобразовываются к строкам под капотом.

JavaScript интерпретирует (или распаковывает) операторы. При использовании квадратных скобок JS замечает [ и продолжает пока не встретит ] . Только после этого он вычислит то, что находится внутри скобок.

mouse[bird.size] : Сперва определяется bird.size , которое равно «small» . mouse[«small»] возвращает true .

Но с записью через точку так не происходит. У mouse нет ключа bird . Таким образом, mouse.bird равно undefined . Затем мы запрашиваем ключ size , используя точечную нотацию: mouse.bird.size . Так как mouse.bird это undefined , мы запрашиваем undefined.size . Это не является валидным, и мы получаем ошибку типа Cannot read property «size» of undefined .

6. Что будет в консоли?

  • A: Hello
  • B: Hey!
  • C: undefined
  • D: ReferenceError
  • E: TypeError

Ответ

В JavaScript все объекты являются ссылочными типами данных.

Сперва переменная c указывает на объект. Затем мы указываем переменной d ссылаться на тот же объект, что и c .

Когда ты изменяешь один объект, то изменяются значения всех ссылок, указывающих на этот объект.

7. Что будет в консоли?

  • A: true false true
  • B: false false true
  • C: true false false
  • D: false true true

Ответ

new Number() это встроенный конструктор функции. И хотя он выглядит как число, это не настоящее число: у него есть ряд дополнительных фич и это объект.

Оператор == разрешает приведение типов, он проверяет равенство значений. Оба значения равны 3 , поэтому возвращается true .

При использовании оператора === значение и тип должны быть одинаковыми. Но в нашем случае это не так: new Number() это не число, это объект. Оба возвращают false .

8. Каким будет результат?

  • A: orange
  • B: purple
  • C: green
  • D: TypeError

Ответ

Функция colorChange является статичной. Статичные методы не имеют доступа к экземплярам класса. Так как freddie это экземпляр, то статичный метод там не доступен. Поэтому выбрасывается ошибка TypeError .

9. Что будет в консоли?

  • A: <>
  • B: ReferenceError: greetign is not defined
  • C: undefined

Ответ

В консоли выведется объект, потому что мы только что создали пустой объект в глобальном объекте! Когда мы вместо greeting написали greetign , интерпретатор JS на самом деле выполнил global.greetign = <> (или window.greetign = <> в браузере).

Нужно использовать «use strict» , чтобы избежать такого поведения. Эта запись поможет быть уверенным в том, что переменная была определена перед тем как ей присвоили значение.

10. Что произойдет?

  • A: Ничего, всё в порядке!
  • B: SyntaxError . Нельзя добавлять свойства функциям таким способом.
  • C: undefined
  • D: ReferenceError

Ответ

В JavaScript это возможно, т.к. функции это объекты! (Всё есть объект кроме примитивов).

Функция — это специальный тип объекта, который можно вызвать. Кроме того, функция — это объект со свойствами. Свойство такого объекта нельзя вызвать, так как оно не является функцией.

11. Что будет в консоли?

  • A: TypeError
  • B: SyntaxError
  • C: Lydia Hallie
  • D: undefined undefined

Ответ

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

сделает метод member.getFullName() рабочим. В чем тут преимущество? Предположим, что мы добавили этот метод к конструктору. Возможно, не каждому экземпляру Person нужен этот метод. Это приведет к большим потерям памяти, т.к. все экземпляры будут иметь это свойство. Напротив, если мы добавим этот метод только к прототипу, у нас будет только одно место в памяти, к которому смогут обращаться все экземпляры!

12. Что будет в консоли?

  • A: Person и undefined
  • B: Person и Person
  • C: Person и <>
  • D: Person и ReferenceError

Ответ

Для sarah мы не использовали ключевое слово new . Использование new приводит к созданию нового объекта. Но без new он указывает на глобальный объект!

Мы указали, что this.firstName равно «Sarah» и this.lastName равно «Smith» . На самом деле мы определили global.firstName = ‘Sarah’ и global.lastName = ‘Smith’ . sarah осталась undefined , поскольку мы не возвращаем значение из функции Person .

13. Назовите три фазы распространения событий

  • A: Цель > Захват > Всплытие
  • B: Всплытие > Цель > Захват
  • C: Цель > Всплытие > Захват
  • D: Захват > Цель > Всплытие

Ответ

Во время фазы захвата событие распространяется с элементов родителей до элемента цели. После достижения цели начинается фаза всплытия.

14. Все объекты имеют прототипы

  • A: Да
  • B: Нет

Ответ

Все объекты имеют прототипы, кроме базового объекта. Базовый объект имеет доступ до некоторых методов и свойств, таких как .toString . Именно поэтому мы можем использовать встроенные методы JavaScript! Все эти методы доступны в прототипе. Если JavaScript не может найти метод непосредственно у объекта, он продолжает поиск по цепочке прототипов пока не найдет.

15. Каким будет результат?

  • A: NaN
  • B: TypeError
  • C: «12»
  • D: 3

Ответ

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

В этом примере JavaScript сконвертировал число 1 в строку, чтобы операция внутри функции имела смысл и вернула значение. Во время сложения числа ( 1 ) и строки ( ‘2’ ) число преобразовывается к строке. Мы можем конкатенировать строки вот так: «Hello» + «World» . Таким образом, «1» + «2» возвращает «12» .

16. Что будет в консоли?

  • A: 1 1 2
  • B: 1 2 2
  • C: 0 2 2
  • D: 0 1 2

Ответ

Постфиксный унарный оператор ++ :

  1. Возвращает значение ( 0 )
  2. Инкрементирует значение (теперь число равно 1 )

Префиксный унарный оператор ++ :

  1. Инкрементирует значение (число теперь равно 2 )
  2. Возвращает значение ( 2 )

Результат: 0 2 2 .

17. Что будет в консоли?

  • A: «Lydia» 21 [«», » is «, » years old»]
  • B: [«», » is «, » years old»] «Lydia» 21
  • C: «Lydia» [«», » is «, » years old»] 21

Ответ

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

18. Что будет в консоли?

  • A: Ты взрослый!
  • B: Ты все еще взрослый.
  • C: Хмм.. Кажется, у тебя нет возраста.

Ответ

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

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

19. Что будет в консоли?

  • A: «number»
  • B: «array»
  • C: «object»
  • D: «NaN»

Ответ

Оператор распространения ( . args ) возвращает массив с аргументами. Массив это объект, поэтому typeof args возвращает «object» .

20. Что будет в консоли?

  • A: 21
  • B: undefined
  • C: ReferenceError
  • D: TypeError

Ответ

Используя «use strict» , можно быть уверенным, что мы по ошибке не побъявим глобальные переменные. Мы ранее нигде не объявляли переменную age , поэтому с использованием «use strict» возникнет ReferenceError . Без использования «use strict» ошибки не возникнет, а переменная age добавится в глобальный объект.

21. Чему будет равно sum ?

  • A: 105
  • B: «105»
  • C: TypeError
  • D: «10*10+5»

Ответ

eval выполняет код, переданный в виде строки. Если это выражение (как в данном случае), то вычисляется выражение. Выражение 10 * 10 + 5 вернет число 105 .

22. Как долго будет доступен cool_secret?

  • A: Всегда, данные не потеряются.
  • B: Пока пользователь не закроет вкладку.
  • C: Пока пользователь не закроет браузер, а не только вкладку.
  • D: Пока пользователь не выключит компьютер.


Ответ

Данные, сохраненные в sessionStorage очищаются после закрытия вкладки.

При использовании localStorage данные сохраняются навсегда. Очистить их можно, например, используя localStorage.clear() .

23. Что будет в консоли?

  • A: 8
  • B: 10
  • C: SyntaxError
  • D: ReferenceError

Ответ

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

Но такой трюк нельзя проделать с let и const , т.к. у них блочная область видимости.

24. Каким будет результат?

  • A: false true false true
  • B: false true true true
  • C: true true false true
  • D: true true true true

Ответ

Все ключи объектов (кроме Symbols) являются строками, даже если заданы не в виде строк. Поэтому obj.hasOwnProperty(‘1’) так же возвращает true.

Но это не работает для set . Значения ‘1’ нет в set : set.has(‘1’) возвращает false . Но set.has(1) вернет true .

25. Что будет в консоли?

  • A:
  • B:
  • C:
  • D: SyntaxError

Ответ

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

26. Глобальный контекст исполнения создает две вещи: глобальный объект и this

  • A: Да
  • B: Нет
  • C: Это зависит

Ответ

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

27. Что будет в консоли?

  • A: 1 2
  • B: 1 2 3
  • C: 1 2 4
  • D: 1 3 4

Ответ

Оператор continue пропускает итерацию, если условие возвращает true .

28. Каким будет результат?

  • A: «Just give Lydia pizza already!»
  • B: TypeError: not a function
  • C: SyntaxError
  • D: undefined

Ответ

String это встроенный конструктор, к которому можно добавлять свойства. Я добавила метод к его прототипу. Строки-примитивы автоматически конвертируются к строкам-объектам. Поэтому все строки (строковые объекты) имеют доступ к этому методу!

29. Что будет в консоли?

  • A: 123
  • B: 456
  • C: undefined
  • D: ReferenceError

Ответ

Ключи объекта автоматически конвертируются в строки. Мы собираемся добавить объект в качестве ключа к объекту a со значением 123 .

Тем не менее, когда мы приводим объект к строке, он становится «[object Object]» . Таким образом, мы говорим, что a[«Object object»] = 123 . Потом мы делаем то же самое. c это другой объект, который мы неявно приводим к строке. Поэтому a[«Object object»] = 456 .

Затем, когда мы выводим a[b] , мы имеем в виду a[«Object object»] . Мы только что установили туда значение 456 , поэтому в результате получаем 456 .

30. Каким будет результат?

  • A: First Second Third
  • B: First Third Second
  • C: Second First Third
  • D: Second Third First

Ответ

Мы вызываем функцию setTimeout первой. Тем не менее, она выводится в консоль последней

Это происходит из-за того, что в браузерах у нас есть не только рантайм движок, но и WebAPI . WebAPI предоставляет нам функцию setTimeout и много других возможностей. Например, DOM.

После того как коллбек отправлен в WebAPI , функция setTimeout (но не коллбек!) вынимается из стека.

Теперь вызывается foo , и «First» выводится в консоль.

foo достается из стека, и вызывается baz . «Third» выводится в консоль.

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

Здесь на сцену выходит цикл событий (event loop). Event loop проверяет стек и очередь задач. Если стек пустой, то он берет первый элемент из очереди и отправляет его в стек.

Вызывается bar , в консоль выводится «Second» и эта функция достается из стека.

31. Что будет в event.target после клика на кнопку?

  • A: Внешний div
  • B: Внутренний div
  • C: button
  • D: Массив со всеми вложенными элементами

Ответ

Целью события является самый глубокий вложенный элемент. Остановить распространение событий можно с помощью event.stopPropagation

32. Что будет в консоли после клика по параграфу?

  • A: p div
  • B: div p
  • C: p
  • D: div

Ответ

После клика по p будет выведено p и div . В цикле жизни события есть три фазы: захват, цель и всплытие. По умолчанию обработчики событий выполняются на фазе всплытия (если не установлен параметр useCapture в true ). Всплытие идет с самого глубокого элемента вверх.

33. Что будет в консоли?

  • A: undefined is 21 Lydia is 21
  • B: function function
  • C: Lydia is 21 Lydia is 21
  • D: Lydia is 21 function

Ответ

В обоих случаях мы передаем объект, на который будет указывать this . Но .call выполняется сразу же!

.bind возвращает копию функции, но с привязанным контекстом. Она не выполняется незамедлительно.

34. Каким будет результат?

  • A: «object»

  • B: «number»
  • C: «function»
  • D: «undefined»

Ответ

Функция sayHi возвращает значение, возвращаемое из немедленно вызываемого функционального выражения (IIFE). Результатом является 0 типа «number» .

Для информации: в JS 7 встроенных типов: null , undefined , boolean , number , string , object , и symbol . «function» не является отдельным типом, т.к. функции являются объектами типа «object» .

35. Какие из этих значений являются «ложными»?

  • A: 0 , » , undefined
  • B: 0 , new Number(0) , » , new Boolean(false) , undefined
  • C: 0 , » , new Boolean(false) , undefined
  • D: Все являются «ложными»

Ответ

Есть только шесть «ложных» значений:

Конструкторы функций, такие как new Number и new Boolean являются «истинными».

36. Что будет в консоли

  • A: «number»
  • B: «string»
  • C: «object»
  • D: «undefined»

Ответ

typeof 1 возвращает «number» . typeof «number» возвращает «string»

37. Что будет в консоли?

  • A: [1, 2, 3, 7 x null, 11]
  • B: [1, 2, 3, 11]
  • C: [1, 2, 3, 7 x empty, 11]
  • D: SyntaxError

Ответ

Когда в массив добавляется значение, которое выходит за пределы длины массива, JavaScript создает так называемые «пустые ячейки». На самом деле они имеют значения undefined , но в консоли выводятся так:

[1, 2, 3, 7 x empty, 11]

в зависимости от окружения (может отличаться для браузеров, Node, и т.д.).

38. Что будет в консоли?

  • A: 1 undefined 2
  • B: undefined undefined undefined
  • C: 1 1 2
  • D: 1 undefined undefined

Ответ

Блок catch получает аргумент x . Это не тот же x , который определен в качестве переменной перед строкой try <

Затем мы присваиваем этому аргументу значение 1 и устанавливаем значение для переменной y . Потом выводим в консоль значение аргумента x , которое равно 1 .

За пределами блока catch переменная x все еще undefined , а y равно 2 . Когда мы вызываем console.log(x) за пределами блока catch , этот вызов возвращает undefined , а y возвращает 2 .

39. Всё в JavaScript это

  • A: примитив или объект
  • B: функция или объект
  • C: вопрос с подвохом! только объекты
  • D: число или объект

Ответ

В JavaScript есть только примитивы и объекты.

Типы примитивов: boolean , null , undefined , bigint , number , string , и symbol .

Отличием примитива от объекта является то, что примитивы не имеют свойств или методов. Тем не менее, ‘foo’.toUpperCase() преобразуется в ‘FOO’ и не вызывает TypeError . Это происходит потому, что при попытке получения свойства или метода у примитива (например, строки), JavaScript неявно обернет примитив объектом, используя один из классов-оберток (например, String ), а затем сразу же уничтожит обертку после вычисления выражения. Все примитивы кроме null и undefined ведут себя таким образом.

40. Каким будет результат?

  • A: [0, 1, 2, 3, 1, 2]
  • B: [6, 1, 2]
  • C: [1, 2, 0, 1, 2, 3]
  • D: [1, 2, 6]

Ответ

[1, 2] — начальное значение, с которым инициализируется переменная acc . После первого прохода acc будет равно [1,2] , а cur будет [0,1] . После конкатенации результат будет [1, 2, 0, 1] .

Затем acc равно [1, 2, 0, 1] , а cur равно [2, 3] . После слияния получим [1, 2, 0, 1, 2, 3] .

41. Каким будет результат?

  • A: false true false
  • B: false false true
  • C: false true true
  • D: true true false

Ответ

null — «ложный». !null возвращает true . !true возвращает false .

«» — «ложный». !»» возвращает true . !true возвращает false .

1 — «истинный». !1 возвращает false . !false возвращает true .

42. Что возвращает метод setInterval ?

  • A: уникальный id
  • B: указанное количество миллисекунд
  • C: переданную функцию
  • D: undefined

Ответ

Это метод возвращает уникальный id. Этот id может быть использован для очищения интервала с помощью функции clearInterval() .

43. Каким будет результат?

  • A: [«L», «y», «d», «i», «a»]
  • B: [«Lydia»]
  • C: [[], «Lydia»]
  • D: [[«L», «y», «d», «i», «a»]]

Ответ

Строка является итерируемой сущностью. Оператор распространения преобразовывает каждый символ в отдельный элемент.

44. Каким будет результат?

  • A: [0, 10], [10, 20]
  • B: 20, 20
  • C: 10, 20
  • D: 0, 10 and 10, 20

Ответ

Обычные функции не могут быть остановлены на полпути после вызова. Однако функцию генератор можно «остановить» на полпути, а затем продолжить с того места, где она остановилась. Каждый раз, когда в функции-генераторе встречает ключевое слово yield , функция возвращает значение, указанное после него. Обратите внимание, что функция генератора в этом случае не return значение, оно yields значение.

Сначала мы инициализируем функцию генератор с i , равным 10 . Мы вызываем функцию генератор, используя метод next () . Когда мы в первый раз вызываем функцию генератора, i равно 10 . Он встречает первое ключевое слово yield , получая значение i . Генератор теперь «приостановлен», и 10 выводится в консоль.

Затем мы снова вызываем функцию с помощью метода next () . Она запускается с того места, где остановилась ранее, все еще с i , равным 10 . Теперь он встречает следующее ключевое слово yield и возвращает i * 2 . i равно 10 , поэтому он возвращает 10 * 2 , то есть 20 . Это приводит к 10, 20.

45. Каким будет результат?

  • A: «один»
  • B: «два»
  • C: «два» «один»
  • D: «один» «два»


Ответ

Когда мы передаем несколько промисов методу Promise.race , он разрешает/отклоняет первый промис, который разрешается/отклоняется. В метод setTimeout мы передаем таймер: 500 мс для первого промиса ( firstPromise ) и 100 мс для второго промиса ( secondPromise ). Это означает, что secondPromise разрешается первым со значением ‘два’ . res теперь содержит значение ‘два’ , которое выводиться в консоль.

46. Каким будет результат?

  • A: null
  • B: [null]
  • C: [<>]
  • D: [< name: "Lydia" >]

Ответ

Сначала мы объявляем переменную person со значением объекта, у которого есть свойство name .

Затем мы объявляем переменную с именем members . Мы устанавливаем первый элемент этого массива равным значению переменной person . Объекты взаимодействуют посредством ссылок при установке их равными друг другу. Когда вы назначаете ссылку из одной переменной в другую, вы создаете копию этой ссылки. (обратите внимание, что у них не одинаковые ссылки!)

Затем мы присваиваем переменной person значение null .

Мы изменили только значение переменной person , а не первый элемент в массиве, поскольку этот элемент имеет другую (скопированную) ссылку на объект. Первый элемент в members по-прежнему содержит ссылку на исходный объект. Когда мы выводим в консоль массив members , первый элемент по-прежнему содержит значение объекта, который выводится в консоль.

47. Каким будет результат?

  • A: < name: "Lydia" >,
  • B: «name», «age»
  • C: «Lydia», 21
  • D: [«name», «Lydia»], [«age», 21]

Ответ

С помощью цикла for-in мы можем перебирать ключи объекта, в данном случае name и age . Под капотом ключи объекта являются строками (если они не являются Symbol). В каждом цикле мы устанавливаем значение item равным текущему ключу, по которому он перебирается. Сначала, item равен name , и выводится в консоль. Затем item равен age , который выводится в консоль.

48. Каким будет результат?

  • A: «345»
  • B: «75»
  • C: 12
  • D: «12»

Ответ

Ассоциативность операторов — это порядок, в котором компилятор оценивает выражения, слева направо или справа налево. Это происходит только в том случае, если все операторы имеют одинаковый приоритет. У нас есть только один тип оператора: + . Кроме того, ассоциативность слева направо.

3 + 4 оценивается первым. Это приводит к числу 7 .

7 + ‘5’ приводит к «75» из-за принуждения. JavaScript преобразует число 7 в строку, см. вопрос 15. Мы можем объединить две строки, используя оператор + . «7» + «5» приводит к «75» .

49. Какое значение num ?

  • A: 42
  • B: «42»
  • C: 7
  • D: NaN

Ответ

Только первые числа в строке возвращаются. На основе системы счисления (второй аргумент, чтобы указать, к какому типу чисел мы хотим его анализировать: основание 10, шестнадцатеричное, восьмеричное, двоичное и т.д.), ParseInt проверяет, являются ли символы в строке допустимыми. Как только он встречает символ, который не является допустимым числом в основании, он прекращает синтаксический анализ и игнорирует следующие символы.

* не является допустимым числом. Он только разбирает «7» в десятичную 7 . num теперь содержит значение 7 .

50. Каким будет результат?

  • A: []
  • B: [null, null, null]
  • C: [undefined, undefined, undefined]
  • D: [ 3 x empty ]

Ответ

При использовании метода map, значение num равно элементу, над которым он в данный момент зацикливается. В этом случае элементы являются числами, поэтому условие оператора if typeof num === «number» возвращает true . Функция map создает новый массив и вставляет значения, возвращаемые функцией.

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

51. Каким будет результат?

  • A: < name: "Lydia" >, «1997»
  • B: < name: "Sarah" >, «1998»
  • C: < name: "Lydia" >, «1998»
  • D: < name: "Sarah" >, «1997»

Ответ

Аргументы передаются значением, если их значение не является объектом, то они передаются ссылкой. birthYear передается по значению, поскольку это строка, а не объект. Когда мы передаем аргументы по значению, создается копия этого значения (см. вопрос 46).

Переменная birthYear имеет ссылку на значение «1997» . Аргумент year также имеет ссылку на значение «1997» , но это не то же самое значение, на которое имеется ссылка для birthYear . Когда мы обновляем значение year , устанавливая year равным «1998» , мы обновляем только значение year . birthYear по-прежнему равно «1997» .

Значение person является объектом. Аргумент member имеет (скопированную) ссылку на тот же объект. Когда мы изменяем свойство объекта, на который member ссылается, значение person также будет изменено, поскольку они оба имеют ссылку на один и тот же объект. Свойство name объекта person теперь равно значению «Lydia» .

52. Каким будет результат?

  • A: It worked! Hello world!
  • B: Oh no an error: undefined
  • C: SyntaxError: can only throw Error objects
  • D: Oh no an error: Hello world!

Ответ

С помощью оператора throw мы можем создавать собственные ошибки. С этим оператором вы можете генерировать исключения. Исключением может быть строка, число, логическое значение или объект. В этом случае нашим исключением является строка ‘Hello world’ .

С помощью оператора catch мы можем указать, что делать, если в блоке try выдается исключение. Исключение: строка ‘Hello world’ . e теперь равно той строке, которую мы записываем. Это приводит к ‘Oh error: Hello world’ .

53. Каким будет результат?

  • A: «Lamborghini»
  • B: «Maserati»
  • C: ReferenceError
  • D: TypeError

Ответ

Когда вы возвращаете свойство, значение свойства равно возвращаемому значению, а не значению, установленному в функции конструктора. Мы возвращаем строку «Maserati» , поэтому myCar.make равно «Maserati» .

54. Каким будет результат?

  • A: «undefined», «number»
  • B: «number», «number»
  • C: «object», «number»
  • D: «number», «undefined»

Ответ

let x = y = 10; на самом деле является сокращением для:

Когда мы устанавливаем y равным 10 , мы фактически добавляем свойство y к глобальному объекту ( window в браузере, global в Node). В браузере window.y теперь равен 10 .

Затем мы объявляем переменную x со значением y , которое равно 10 . Переменные, объявленные с ключевым словом let , имеют блочную видимость, они определены только в блоке, в котором они объявлены; немедленно вызванная функция (IIFE) в этом случае. Когда мы используем оператор typeof , операнд x не определен: мы пытаемся получить доступ к x вне блока, в котором он объявлен. Это означает, что x не определен. Значения, которым не присвоено или не объявлено значение, имеют тип «undefined» . console.log(typeof x) возвращает «undefined» .

Однако мы создали глобальную переменную y , установив y равным 10 . Это значение доступно в любом месте нашего кода. y определен и содержит значение типа «number» . console.log(typeof y) возвращает «number» .

55. Какой будет вывод?

  • A: «Woof I am Mara» , TypeError
  • B: «Woof I am Mara» , «Woof I am Mara»
  • C: «Woof I am Mara» , undefined
  • D: TypeError , TypeError

Ответ

Мы можем удалить свойства из объектов, используя ключевое слово delete , также в прототипе. Удаляя свойство в прототипе, оно больше не доступно в цепочке прототипов. В этом случае функция bark больше не доступна в прототипе после delete Dog.prototype.bark , но мы все еще пытаемся получить к ней доступ.

Когда мы пытаемся вызвать что-то, что не является функцией, выдается TypeError . В этом случае TypeError: pet.bark не является функцией , поскольку pet.bark является undefined .

56. Какой будет вывод?

  • A: [1, 1, 2, 3, 4]
  • B: [1, 2, 3, 4]
  • C:
  • D:

Ответ

Объект Set является коллекцией unique значений: значение может появляться только один раз в наборе.

Мы передали последовательность [1, 1, 2, 3, 4] с повторяющимся значением 1 . Поскольку в наборе не может быть двух одинаковых значений, одно из них удаляется. Это приводит к <1, 2, 3, 4>.


57. Какой будет вывод?

  • A: 10
  • B: 11
  • C: Error
  • D: NaN

Ответ

Импортированный модуль является read-only: вы не можете изменить импортированный модуль. Только модуль, который их экспортирует, может изменить его значение.

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

58. Какой будет вывод?

  • A: false , true
  • B: «Lydia» , 21
  • C: true , true
  • D: undefined , undefined

Ответ

Оператор delete возвращает логическое значение: true при успешном удалении, иначе он вернет false . Однако переменные, объявленные с ключевым словом var , const или let , не могут быть удалены с помощью оператора delete .

Переменная name была объявлена ​​с ключевым словом const , поэтому ее удаление не было успешным: возвращается false . Когда мы устанавливаем age равным 21 , мы фактически добавляем свойство с именем age к глобальному объекту. Вы можете успешно удалить свойства из объектов, в том числе из глобального объекта, поэтому delete age возвращает true .

59. Какой будет вывод?

  • A: [[1, 2, 3, 4, 5]]
  • B: [1, 2, 3, 4, 5]
  • C: 1
  • D: [1]

Ответ

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

Значение a теперь равно 1 , а значение b теперь равно 2 . Что мы на самом деле сделали в этом вопросе, так это:

Это означает, что значение y равно первому значению в массиве, которое является числом 1 . Когда мы регистрируем y , возвращается 1 .

60. Какой будет вывод?

  • A: < admin: true, user: < name: "Lydia", age: 21 >>
  • B:
  • C:
  • D:

Ответ

Можно комбинировать объекты с помощью оператора распространения . . Это позволяет создавать копии пар ключ/значение одного объекта и добавлять их в другой объект. В этом случае мы создаем копии объекта user и добавляем их в объект admin . Объект admin теперь содержит скопированные пары ключ/значение, что приводит к .

61. Какой будет вывод?

  • A: < name: "Lydia", age: 21 >, [«name», «age»]
  • B: < name: "Lydia", age: 21 >, [«name»]
  • C: < name: "Lydia">, [«name», «age»]
  • D: < name: "Lydia">, [«age»]

Ответ

С помощью метода defineProperty мы можем добавлять новые свойства к объекту или изменять существующие. Когда мы добавляем свойство к объекту с помощью метода defineProperty , они по умолчанию не перечисляемые. Метод Object.keys возвращает все имена enumerable свойств объекта, в данном случае только «name» .

Свойства, добавленные с помощью метода defineProperty , по умолчанию неизменны. Вы можете переопределить это поведение, используя свойства writable , configurable и enumerable . Таким образом, метод defineProperty дает вам гораздо больший контроль над свойствами, которые вы добавляете к объекту.

62. Какой будет вывод?

  • A: «<"level":19, "health":90>«
  • B: «<"username": "lydiahallie">«
  • C: «[«level», «health»]»
  • D: «<"username": "lydiahallie", "level":19, "health":90>«

Ответ

Второй аргумент JSON.stringify — это replacer. Заменитель может быть либо функцией, либо массивом, и позволяет вам контролировать, что и как должны быть преобразованы в значения.

Если заменитель является массивом, только свойства, имена которых включены в массив, будут добавлены в строку JSON. В этом случае включаются только свойства с именами «level» и «health» , «username» исключается. data теперь равен «<"level":19, "health":90>» .

Если заменитель является function, эта функция вызывается для каждого свойства объекта, который вы преобразуете. Значение, возвращаемое из этой функции, будет значением свойства при добавлении в строку JSON. Если значение равно undefined, это свойство исключается из строки JSON.

63. Какой будет вывод?

  • A: 10 , 10
  • B: 10 , 11
  • C: 11 , 11
  • D: 11 , 12

Ответ

Унарный оператор ++ first возвращает значение операнда, then приращивает значение операнда. Значение num1 равно 10 , так как функция увеличений вначале возвращает значение num , которое равно 10 , и только затем увеличивает значение num .

num2 — это 10 , так как мы передали num1 в incpasePassedNumber . number равно 10 (значение num1 . Опять же, унарный оператор ++ first возвращает значение операнда, _then увеличивает значение операнда. Значение number равно 10 , поэтому num2 равно 10 .

64. Какой будет вывод?

  • A: 20 , 40 , 80 , 160
  • B: 20 , 40 , 20 , 40
  • C: 20 , 20 , 20 , 40
  • D: NaN , NaN , 20 , 40

Ответ

В ES6 мы можем инициализировать параметры значением по умолчанию. Значением параметра будет значение по умолчанию, если никакое другое значение не было передано функции, или если значение параметра равно «undefined» . В этом случае мы распространяем свойства объекта value на новый объект, поэтому значение x по умолчанию равно .

Аргумент по умолчанию реализуется в момент call time! Каждый раз, когда мы вызываем функцию, создается new объект. Мы вызываем функцию multiply первые два раза, не передавая значение: x имеет значение по умолчанию . Затем мы записываем умноженное значение этого числа, которое равно 20 .

В третий раз, когда мы вызываем multiply, мы передаем аргумент: объект с именем value . Оператор *= на самом деле является сокращением для x.number = x.number * 2 : мы изменяем значение x.number и записываем умноженное значение 20 .

В четвертый раз мы снова передаем объект value . x.number ранее был изменен на 20 , поэтому x.number * = 2 записывает 40 .

65. Какой будет вывод?

  • A: 1 2 , 3 3 и 6 4
  • B: 1 2 , 2 3 и 3 4
  • C: 1 undefined , 2 undefined , 3 undefined и 4 undefined
  • D: 1 2 , undefined 3 и undefined 4

Ответ

Первым аргументом, который получает метод reduce , является аккумулятором, в данном случае x . Второй аргумент — это текущее значение, y . С помощью метода reduce мы выполняем функцию обратного вызова для каждого элемента в массиве, что в конечном итоге может привести к единственному значению.

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

Значение аккумулятора равно ранее возвращенному значению функции обратного вызова. Если вы не передадите необязательный аргумент initialValue методу reduce , аккумулятор будет равен первому элементу при первом вызове.

При первом вызове аккумулятор ( x ) равен 1 , а текущее значение ( y ) равно 2 . Мы не возвращаемся из функции обратного вызова, мы регистрируем аккумулятор и текущее значение: 1 и 2 регистрируются.

Если вы не возвращаете значение из функции, она возвращает значение undefined . При следующем вызове аккумулятор равен undefined , а текущее значение равно 3. undefined и 3 будут зарегистрированы.

При четвертом вызове мы снова не возвращаемся из функции обратного вызова. Аккумулятор снова равен undefined , а текущее значение равно 4 . undefined и 4 будут зарегистрированы.

66. С помощью какого конструктора мы можем успешно расширить класс Dog ?

  • A: 1
  • B: 2
  • C: 3
  • D: 4

Ответ

В производном классе вы не можете получить доступ к ключевому слову this до вызова super . Если вы попытаетесь это сделать, он выдаст ReferenceError: 1 и 4 приведут к ошибке ссылки.

С ключевым словом super мы вызываем конструктор родительского класса с заданными аргументами. Конструктор родителя получает аргумент name , поэтому нам нужно передать name в super .

Класс Labrador получает два аргумента: name , поскольку он расширяет Dog , и size в качестве дополнительного свойства класса Labrador . Они оба должны быть переданы в функцию конструктора в Labrador , что делается правильно с помощью конструктора 2.

67. Какой будет вывод?

  • A: running index.js , running sum.js , 3
  • B: running sum.js , running index.js , 3
  • C: running sum.js , 3 , running index.js
  • D: running index.js , undefined , running sum.js

Ответ

С ключевым словом import все импортируемые модули являются pre-parsed. Это означает, что импортированные модули запускаются первыми, код в файле, который импортирует модуль, исполняется после.

В этом разница между require() в CommonJS и import ! С помощью require() вы можете загружать зависимости по требованию во время выполнения кода. Если бы мы использовали require вместо import , в консоль были бы записаны running index.js , running sum.js , 3 .

68. Какой будет вывод?

  • A: true , true , false
  • B: false , true , false
  • C: true , false , true
  • D: true , true , true

Ответ

Каждый Symbol совершенно уникален. Цель аргумента, переданного Symbol , состоит в том, чтобы дать Symbol описание. Значение Symbol не зависит от переданного аргумента. Когда мы проверяем равенство, мы создаем два совершенно новых Symbol : первый Symbol(‘foo’) и второй Symbol(‘foo’) . Эти два значения уникальны и не равны друг другу, Symbol(‘foo’) === Symbol(‘foo’) возвращает false .

69. Какой будет вывод?

  • A: «Lydia Hallie» , «Lydia Hallie»
  • B: » Lydia Hallie» , » Lydia Hallie» ( «[13x whitespace]Lydia Hallie» , «[2x whitespace]Lydia Hallie» )
  • C: » Lydia Hallie» , «Lydia Hallie» ( «[1x whitespace]Lydia Hallie» , «Lydia Hallie» )
  • D: «Lydia Hallie» , «Lyd» ,

Ответ

С помощью метода padStart мы можем добавить отступ в начало строки. Значение, передаваемое этому методу, представляет собой общую длину строки вместе с отступом. Строка «Lydia Hallie» имеет длину 12 . name.padStart(13) вставляет 1 пробел в начале строки, потому что 12 + 1 равно 13.

Если аргумент, переданный методу padStart , меньше длины строки, заполнение не будет добавлено.

70. Какой будет вывод?

  • A: «����»
  • B: 257548
  • C: Строка, содержащая кодовые обозначения
  • D: Error

Ответ

С помощью оператора + вы можете объединять строки. В этом случае мы объединяем строку «» со строкой «��» , что приводит к «��» .

71. Как мы можем вывести в лог значения, которые закомментированы после оператора console.log?

  • A: game.next(«Yes»).value и game.next().value
  • B: game.next.value(«Yes») и game.next.value()
  • C: game.next().value и game.next(«Yes»).value
  • D: game.next.value() и game.next.value(«Yes»)

Ответ

Функция генератора «приостанавливает» выполнение, когда видит ключевое слово yield. Во-первых, мы должны позволить функции выдать строку «Do you love JavaScript?», что можно сделать, вызвав game.next().value .

Каждая строка выполняется до тех пор, пока не найдет первое ключевое слово yield . В первой строке функции есть ключевое слово yield на первом месте: выполнение останавливается с первым выходом! Это означает, что переменная answer еще не определена!

Когда мы вызываем game.next(«Yes»).value , предыдущий yield заменяется значением параметров, переданных функции next() , в данном случае «Yes» . Значение переменной answer теперь равно «Yes» . Условие if возвращает false , а JavaScript loves you back ❤️ , регистрируется.

72. Какой будет вывод?

  • A: Hello world!
  • B: Hello
    world
  • C: Hello\nworld
  • D: Hello\n
    world

Ответ

String.raw возвращает строку, в которой экранированные символы ( \n , \v , \t и т.д.) игнорируются! Обратная косая черта может быть проблемой, так как вы можете получить что-то вроде:

const path = `C:\Documents\Projects\table.html`

С String.raw он просто проигнорирует управляющий знак и напечатает:

В этом случае строка Hello\nworld , которая и выводится.

73. Какой будет вывод?

  • A: «I made it!»
  • B: Promise
  • C: Promise <

Асинхронная функция всегда возвращает обещание. await все еще должен ждать разрешения обещания: ожидаемое обещание возвращается, когда мы вызываем getData() , чтобы установить data равным ему.

Если бы мы хотели получить доступ к разрешенному значению «I made it» , мы могли бы использовать метод .then() для data :

Тогда это бы вывело «I made it!»

74. Какой будет вывод?

  • A: [‘apple’, ‘banana’]
  • B: 2
  • C: true
  • D: undefined

Ответ

Метод .push() возвращает длину нового массива! Ранее массив содержал один элемент (строка «banana» ) и имел длину 1 . После добавления в массив строки «apple» , массив содержит два элемента и имеет длину 2 . Это возвращается из функции addToList .

Метод push изменяет исходный массив. Если вы хотите вернуть массив из функции, а не длину массива, вы должны были вернуть list после добавления в нее item .

75. Какой будет вывод?

  • A:
  • B:
  • C:
  • D: ReferenceError

Ответ

Object.freeze делает невозможным добавление, удаление или изменение свойств объекта (если только значение свойства не является другим объектом).

Когда мы создаем переменную shape и устанавливаем ее равной замороженному объекту box , shape также ссылается на замороженный объект. Вы можете проверить, заморожен ли объект, используя Object.isFrozen . В этом случае Object.isFrozen(shape) возвращает true, поскольку переменная shape имеет ссылку на замороженный объект.

Поскольку shape заморожен, и поскольку значение x не является объектом, мы не можем изменить свойство x . x по-прежнему равно 10 , и регистрируется.

76. Какой будет вывод?

  • A: «Lydia»
  • B: «myName»
  • C: undefined
  • D: ReferenceError

Ответ

Когда мы распаковываем свойство name из правого объекта, мы присваиваем его значение «Lydia» переменной с именем myName .

С помощью мы сообщаем JavaScript, что хотим создать новую переменную с именем myName со значением свойства name в правой части.

Поскольку мы пытаемся зарегистрировать name , переменную, которая не определена, выдается ReferenceError.

77. Это чистая функция?

  • A: Да
  • B: Нет

Ответ

Чистая функция — это функция, которая всегда возвращает тот же результат, если переданы одинаковые аргументы.

Функция sum всегда возвращает один и тот же результат. Если мы передадим 1 и 2 , он всегда вернет 3 без побочных эффектов. Если мы передадим 5 и 10 , он всегда вернет 15 и так далее. Это определение чистой функции.

78. Какой будет вывод?

  • A: Calculated! 20 Calculated! 20 Calculated! 20
  • B: Calculated! 20 From cache! 20 Calculated! 20
  • C: Calculated! 20 From cache! 20 From cache! 20
  • D: Calculated! 20 From cache! 20 Error

Ответ

Функция add является функцией запоминателем. С помощью запоминания мы можем кэшировать результаты функции, чтобы ускорить ее выполнение. В этом случае мы создаем объект cache , в котором хранятся ранее возвращенные значения.

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

Мы вызываем функцию addFunction три раза с одним и тем же значением: при первом вызове значение функции, когда num равно 10 , еще не кэшировано. Условие оператора if num in cache возвращает false , и выполняется блок else: Calculated! 20 регистрируется, и значение результата добавляется в объект кеша. cache теперь выглядит как <10: 20>.

Во второй раз объект cache содержит значение, возвращаемое для 10 . Условие оператора if num in cache возвращает true , а ‘From cache! 20’ выводится в лог.

В третий раз мы передаем 5 * 2 в функцию, которая оценивается как 10 . Объект cache содержит значение, возвращаемое для 10 . Условие оператора if num in cache возвращает true , а ‘From cache! 20’ регистрируется.

79. Какой будет вывод?

  • A: 0 1 2 3 и «☕» «��» «��» «��»
  • B: «☕» «��» «��» «��» и «☕» «��» «��» «��»
  • C: «☕» «��» «��» «��» и 0 1 2 3
  • D: 0 1 2 3 и

Ответ

С помощью цикла for-in мы можем перебирать перечисляемые свойства. В массиве перечисляемые свойства являются «ключами» элементов массива, которые фактически являются их индексами. Вы можете увидеть массив как:

Где ключи — перечисляемые свойства. 0 1 2 3 войти в систему.

С помощью цикла for-of мы можем выполнять итерацию итераций. Массив является итеративным. Когда мы выполняем итерацию по массиву, переменная «item» равна элементу, по которому она итерируется в данный момент, «☕» «��» «��» «��» выводится в лог.

80. Какой будет вывод?

  • A: [«1 + 2», «1 * 2», «1 / 2»]
  • B: [«12», 2, 0.5]
  • C: [3, 2, 0.5]
  • D: [1, 1, 1]

Ответ

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

Элемент будет равен возвращаемому значению. 1 + 2 вернет 3 , 1 * 2 вернет 2 , а 1 / 2 вернет 0.5 .

81. Какой будет вывод?

  • A: Hello there,
  • B: Hello there, undefined
  • C: Hello there, null
  • D: ReferenceError

Ответ

По умолчанию аргументы имеют значение undefined , если только значение не было передано функции. В этом случае мы не передали значение для аргумента name . name равно логгируемому undefined .

В ES6 мы можем перезаписать значение по умолчанию undefined параметрами по умолчанию. Например:

function sayHi(name = «Lydia»)

В этом случае, если мы не передали значение или если мы передали undefined , name всегда будет равно строке Lydia

82. Какой будет вывод?

  • A: «��» и «��»
  • B: «��» и «��»
  • C: «��» и «��»
  • D: «��» и «��»

Ответ

Значение ключевого слова this зависит от того, где вы его используете. В методе, как и в методе getStatus , ключевое слово this ссылается на объект, которому принадлежит метод. Метод принадлежит объекту data , поэтому this относится к объекту data . Когда мы регистрируем this.status , регистрируется свойство status объекта data , которое является «��» .

С помощью метода call мы можем изменить объект, на который ссылается ключевое слово this . В функциях ключевое слово this относится к объекту, которому принадлежит функция. Мы объявили функцию setTimeout для объекта global, поэтому в функции setTimeout ключевое слово this ссылается на объект global. В глобальном объекте есть переменная с именем status со значением «��» . При регистрации this.status выводится «��» .

83. Какой будет вывод?

  • A:
  • B:
  • C:
  • D: «Amsterdam»

Ответ

Мы устанавливаем переменную city равной значению свойства с именем city для объекта person . У этого объекта нет свойства с именем city , поэтому переменная city имеет значение undefined .

Обратите внимание, что мы не ссылаемся на сам объект person! Мы просто устанавливаем переменную city равной текущему значению свойства city объекта person .

Затем мы устанавливаем city равным строке «Amsterdam» . Это не меняет объект person — нет ссылки на этот объект.

При регистрации объекта person возвращается неизмененный объект.

84. Какой будет вывод?

  • A: «Sorry, you’re too young.»
  • B: «Yay! You’re old enough!»
  • C: ReferenceError
  • D: undefined

Ответ

Переменные с ключевыми словами const и let имеют блочную видимость. Блок — это что-то между фигурными скобками ( <> ). В этом случае в фигурных скобках операторов if/else. Вы не можете ссылаться на переменную за пределами блока, в котором она объявлена, вызывается ReferenceError.

85. Какая информация будетвыведена в лог?

  • A: Результат метода fetch .
  • B: Результат второго вызова метода fetch .
  • C: Результат коллбэка в предыдущем .then() .
  • D: Всегда будет undefined .

Ответ

Значение res во втором .then равно возвращенному значению предыдущего .then . Вы можете продолжать цепочку .then таким образом; значение передается следующему обработчику.

86. Какая опция позволяет установить hasName равным true , если вы не можете передать true в качестве аргумента?

  • A: !!name
  • B: name
  • C: new Boolean(name)
  • D: name.length

Ответ

С помощью !!name мы определяем, является ли значение name истинным или ложным. Если имя истинное, которое мы хотим проверить, то !name возвращает false . А !false (это то, чем на самом деле является !! name ) возвращает true .

Устанавливая hasName равным name , вы устанавливаете hasName равным любому значению, которое вы передали функции getName , а не логическому значению true .

new Boolean (true) возвращает объектную оболочку, а не само логическое значение.

name.length возвращает длину переданного аргумента, независимо от того, является ли он true .

87. Какой будет вывод?

  • A: «»»
  • B: «I»
  • C: SyntaxError
  • D: undefined

Ответ

Чтобы получить символ по определенному индексу в строке, вы можете использовать скобочную нотацию. Первый символ в строке имеет индекс 0 и т.д. В этом случае мы хотим получить элемент с индексом 0, символ ‘I’ , который выводится в лог.

Обратите внимание, что этот метод не поддерживается в IE7 и ниже. В этом случае используйте .charAt()

88. Какой будет вывод?

  • A: NaN
  • B: 20
  • C: ReferenceError
  • D: undefined

Ответ

Вы можете установить значение параметра по умолчанию равным другому параметру функции, если они были определены до параметров по умолчанию. Мы передаем значение 10 в функцию sum . Если функция sum принимает только один аргумент, это означает, что значение для num2 не передано, и в этом случае значение num1 равно переданному значению 10 . Значением по умолчанию num2 является значение num1 , которое равно 10 . num1 + num2 возвращает 20 .

Если вы пытаетесь установить значение параметра по умолчанию равным параметру, который определен после (справа), то значение параметра еще не было инициализировано; это приведет к ошибке.

89. Какой будет вывод?

  • A:
  • B:
  • C:
  • D: Global object of module.js

Ответ

С синтаксисом import * as name мы импортируем все exports из файла module.js в файл index.js , тогда и создается новый объект с именем data . В файле module.js есть два экспорта: экспорт по умолчанию и именованный экспорт. Экспорт по умолчанию — это функция, которая возвращает строку «Hello World» , а именованный экспорт — это переменная с именем name , которая имеет значение строки «Lydia» .

Объект data имеет свойство default для экспорта по умолчанию, другие свойства имеют имена именованных экспортов и их соответствующие значения.

90. Какой будет вывод?

  • A: «class»
  • B: «function»
  • C: «object»
  • D: «string»

Ответ

Классы являются синтаксическим сахаром для конструкторов функций. Эквивалентом класса Person в качестве конструктора функции будет:

Вызов конструктора функции с new приводит к созданию экземпляра Person , ключевое слово typeof возвращает «object» для экземпляра. typeof member возвращает «объект» .

91. Какой будет вывод?

  • A: [1, 2, 3, 4, 5]
  • B: [1, 2, 3, 5]
  • C: [1, 2, 3, 4]
  • D: Error

Ответ

Метод .push возвращает новую длину массива, а не сам массив! Устанавливая newList равным [1, 2, 3].push(4) , мы устанавливаем newList равным новой длине массива: 4 .

Затем мы пытаемся использовать метод .push для newList . Поскольку newList является числовым значением 4 , мы не можем использовать метод .push : выдается ошибка TypeError.

92. Какой будет вывод?

  • A: < constructor: . >
  • B: <>
  • C: < constructor: . ><>
  • D: < constructor: . >undefined

Ответ

Обычные функции, такие как функция giveLydiaPizza , имеют свойство prototype , которое является объектом (прототипом объекта) со свойством constructor . Однако функции со стрелками, такие как функция giveLydiaChocolate , не имеют этого свойства prototype . undefined возвращается при попытке доступа к свойству prototype с использованием giveLydiaChocolate.prototype .

93. Какой будет вывод?

  • A: name Lydia and age 21
  • B: [«name», «Lydia»] and [«age», 21]
  • C: [«name», «age»] and undefined
  • D: Error

Ответ

Object.entries (person) возвращает массив вложенных массивов, содержащий ключи и объекты:

[ [ ‘name’, ‘Lydia’ ], [ ‘age’, 21 ] ]

Используя цикл for-of , мы можем перебирать каждый элемент массива, в данном случае подмассивы. Мы можем мгновенно деструктурировать подмассивы в цикле for, используя const [x, y] . x равен первому элементу в подмассиве, y равен второму элементу в подмассиве.

Первым подмассивом является [ «name», «Lydia» ] , где x равно «name» , и y равно «Lydia» , которые выводятся в лог. Вторым подмассивом является [ «age», 21 ] , где x равно «age» , и y равно 21 , которые выводятся в лог.

94. Какой будет вывод?

  • A: [«banana», «apple», «pear», «orange»]
  • B: [[«banana», «apple»], «pear», «orange»]
  • C: [«banana», «apple», [«pear»], «orange»]
  • D: SyntaxError

Ответ

. args — прочие параметры. Значение прочих параметров — это массив, содержащий все оставшиеся аргументы и может быть передан только последним! В этом примере прочие параметры были вторым аргументом. Это невозможно, и это приведет к синтаксической ошибке.

Приведенный выше пример работает. Это возвращает массив [ ‘banana’, ‘apple’, ‘orange’, ‘pear’ ]

95. Какой будет вывод?

  • A: a is bigger , 6 and b is bigger , 3
  • B: a is bigger , undefined and b is bigger , undefined
  • C: undefined and undefined
  • D: SyntaxError

Ответ

В JavaScript мы не должны явно указывать точку с запятой ( ; ), однако движок JavaScript все равно добавляет их после операторов. Это называется автоматической вставкой точек с запятой. Например, оператором могут быть переменные или ключевые слова, такие как throw , return , break и т.д.

Здесь мы написали инструкцию return и другое значение a + b в новой строке. Однако, поскольку это новая линия, движок не знает, что это на самом деле значение, которое мы хотели бы вернуть. Вместо этого он автоматически добавляет точку с запятой после return . Вы можете увидеть это как:

Это означает, что a + b никогда не достигается, так как функция перестает выполняться после ключевого слова return . Если значение не возвращается, как здесь, функция возвращает значение undefined . Обратите внимание, что после операторов if / else автоматической вставки нет!

96. Какой будет вывод?

  • A: «Lydia»
  • B: «Sarah»
  • C: Error: cannot redeclare Person
  • D: SyntaxError

Ответ

Мы можем установить классы равными другим классам/конструкторам функций. В этом случае мы устанавливаем Person равным AnotherPerson . Свойство name этого конструктора — Sarah , поэтому свойство name для нового экземпляра класса Person member — это Sarah .

97. Какой будет вывод?

  • A: and [»
  • B: <> and []
  • C: < a: "b" >and [«a»]
  • D: and []

Ответ

Symbol не является перечисляемый. Метод Object.keys возвращает все перечисляемые свойства ключа для объекта. Symbol не просматривается таким образом, и возвращается пустой массив. При регистрации всего объекта будут видны все свойства, даже не перечисляемые.

Это одно из многих качеств символа: помимо представления совершенно уникального значения (которое предотвращает случайное столкновение имен в объектах, например, при работе с 2 библиотеками, которые хотят добавить свойства к одному и тому же объекту), вы также можете «скрыть» свойства объектов таким образом (хотя и не полностью. Вы можете получить доступ к символам, используя метод Object.getOwnPropertySymbols() ).

98. Какой будет вывод?

  • A: [1, [2, 3, 4]] and undefined
  • B: [1, [2, 3, 4]] and
  • C: [1, 2, 3, 4] and
  • D: Error and

Ответ

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

С помощью оставшихся параметров . y мы помещаем все «оставшиеся» аргументы в массив. Остальные аргументы — это 2 , 3 и 4 в этом случае. Значение y является массивом, содержащим все остальные параметры. В этом случае значение x равно 1 , поэтому, мы видим в логе [x, y] , [1, [2, 3, 4]] .

Функция getUser получает объект. В случае функций со стрелками мы не можем писать фигурные скобки, если мы просто возвращаем одно значение. Однако, если вы хотите вернуть объект из стрелочной функции, вы должны написать его в скобках, в противном случае никакое значение не возвращается! Следующая функция вернула бы объект:

Поскольку в этом случае значение не возвращается, функция возвращает значение undefined .

99. Какой будет вывод?

  • A: SyntaxError
  • B: ReferenceError
  • C: TypeError
  • D: undefined

Ответ

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

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

Синтаксические ошибки генерируются, когда вы написали что-то, что не является допустимым JavaScript, например, когда вы написали слово return как retrun . ReferenceErrors генерируется, когда JavaScript не может найти ссылку на значение, к которому вы пытаетесь получить доступ.

100. Какое значение будет на выходе?

  • A: possible! You should see a therapist after so much JavaScript lol
  • B: Impossible! You should see a therapist after so much JavaScript lol
  • C: possible! You shouldn’t see a therapist after so much JavaScript lol
  • D: Impossible! You shouldn’t see a therapist after so much JavaScript lol

Ответ

[] — истинное значение. С оператором && будет возвращено правое значение, если левое значение является истинным значением. В этом случае левое значение [] является истинным значением, поэтому возвращается ‘Im’ .

«» — ложное значение. Если левое значение ложно, ничего не возвращается. n’t не возвращается.

101. Какое значение будет на выходе?

  • A: false null []
  • B: null «» true
  • C: <> «» []
  • D: null null true

Ответ

С помощью оператора || мы можем вернуть первый истинный операнд. Если все значения ложны, последний операнд возвращается.

(false || <> || null) : пустой объект <> является истинным значением. Это первое (и единственное) истинное значение, которое возвращается. one содержит <> .

(null || false ||» «) : все операнды являются ложными значениями. Это означает, что прошедший операнд «» возвращается. two содержит «» .

([] || 0 ||» «) : пустой массив [] является истинным значением. Это первое истинное значение, которое возвращается. three присвоено [] .

102. Какое значение будет на выходе?

  • A: I have resolved! , second and I have resolved! , second
  • B: second , I have resolved! and second , I have resolved!
  • C: I have resolved! , second and second , I have resolved!
  • D: second , I have resolved! and I have resolved! , second

Ответ

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

Мы можем получить это значение с помощью ключевого слова .then и await в функции async . Хотя мы можем получить значение обещания с помощью .then и await , они работают немного по-разному.

В firstFunction мы (вроде) отложили функцию myPromise во время ее работы, но продолжили выполнение другого кода, в данном случае console.log (‘second’) . Затем функция разрешается строкой I have resolved , которая затем логируется после того, как она увидела, что стек вызовов пуст.

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

Это означает, что мы ожидали разрешения myPromise со значением I have resolved , и только когда это произошло, мы перешли к следующей строке: second была выведена в консоль последней.

103. Какое значение будет на выходе?

  • A: 3 , NaN , NaN
  • B: 3 , 7 , NaN
  • C: 3 , Lydia2 , [Object object]2
  • D: «12» , Lydia2 , [Object object]2

Ответ

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

Первым является 1 , который является числовым значением. 1 + 2 возвращает число 3 .

Тем не менее, вторая строка «Lydia» . «Lydia» является строкой, а 2 является числом: 2 приводится к строке. «Lydia» и «2» объединяются, что приводит к результирующей строке «Lydia2» .

является объектом. Ни число, ни объект не являются строкой, поэтому они приводятся к строке. Всякий раз, когда мы приводим обычный объект, он становится «[Object object]» . «[Object object]» , объединенный с «2» , становится «[Object object]2» .

104. Чему равно значение?

  • A: 5
  • B: Promise <

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

В этом случае мы просто передали числовое значение 5 . Возвращается разрешенное обещание со значением 5 .

105. Чему равно значение?

  • A: Not the same!
  • B: They are the same!
  • C: ReferenceError
  • D: SyntaxError

Ответ

Объекты передаются по ссылке. Когда мы проверяем объекты на строгое равенство ( === ), мы сравниваем их ссылки.

Мы устанавливаем значение по умолчанию для person2 , равное объекту person , и передаем объект person в качестве значения для person1 .

Это означает, что оба значения имеют ссылку на одно и то же место в памяти, поэтому они равны.

Блок кода в операторе else запускается, и в лог выводится They are the same! .

106. Чему равно значение?

  • A: true
  • B: false
  • C: undefined
  • D: TypeError

Ответ

В JavaScript у нас есть два способа доступа к свойствам объекта: нотация в скобках или нотация в точках. В этом примере мы используем точечную нотацию ( colorConfig.colors ) вместо скобочной нотации ( colorConfig[«colors»] ).

В точечной нотации JavaScript пытается найти свойство объекта с таким точным именем. В этом примере JavaScript пытается найти свойство с именем colors в объекте colorConfig . Не существует свойства с именем colorConfig , поэтому возвращается undefined . Затем мы пытаемся получить доступ к значению первого элемента, используя [1] . Мы не можем сделать это для значения, которое undefined , поэтому оно выдает TypeError : Cannot read свойство ‘1’ of undefined .

JavaScript интерпретирует (или распаковывает) операторы. Когда мы используем скобочные обозначения, он видит первую открывающую скобку [ и продолжает работать, пока не найдет закрывающую скобку ] . Только тогда он оценит утверждение. Если бы мы использовали colorConfig[colors [1]] , он бы возвратил значение свойства red объекта colorConfig .

107. Чему равно значение?

  • A: true
  • B: false

Ответ

Под капотом смайлики — это юникоды. Юникод для сердца смайликов «U+2764 U+FE0F» . Они всегда одинаковы для одного и того же смайлика, поэтому мы сравниваем две одинаковые строки друг с другом, что возвращает true .

108. Какой из этих методов модифицирует исходный массив?

  • A: All of them
  • B: map reduce slice splice
  • C: map slice splice
  • D: splice

Ответ

Используя метод splice , мы модифицируем исходный массив, удаляя, заменяя или добавляя элементы. В этом случае мы удалили 2 элемента из индекса 1 (мы удалили ‘��’ и ‘��’ ) и добавили ✨ emoji.

map , filter и slice возвращают новый массив, find возвращает элемент, а reduce возвращает аккумулированное значение.

109. Какое значение будет на выходе?

  • A: [‘��’, ‘��’, ‘��’, ‘��’]
  • B: [‘��’, ‘��’, ‘��’, ‘��’]
  • C: [‘��’, ‘��’, ‘��’, ‘��’, ‘��’]
  • D: ReferenceError

Ответ

Мы устанавливаем значение свойства favourFood для объекта info равным строке со смайликами для пиццы, ‘��’ . Строка является примитивным типом данных. В JavaScript примитивные типы данных передаются по ссылке .

В JavaScript примитивные типы данных (все, что не является объектом) передаются как значение. В этом случае мы устанавливаем значение свойства favourFood объекта info равным значению первого элемента в массиве food , в данном случае это строка с emoji пиццы ( ‘��’ ). Строка является примитивным типом данных и взаимодействует по значению (см. мой пост в блоге, если вы заинтересованы в получении дополнительной информации).

Затем мы меняем значение свойства favourFood объекта info . Массив food не изменился, поскольку значение favourFood было просто скопировано из значения первого элемента в массиве и не имеет ссылки на то же место в памяти, что и элемент на food[0] . Когда мы выводим в лог food , это все равно исходный массив, [‘��’, ‘��’, ‘��’, ‘��’] .

110. Что делает этот метод?

  • A: Разбирает JSON в значение JavaScript
  • B: Разбирает объект JavaScript в JSON
  • C: Разбирает любое значение JavaScript в JSON
  • D: Разбирает JSON непосредственно в объект JavaScript

Ответ

С помощью метода JSON.parse () мы можем разобрать строку JSON в значение JavaScript.

111. Какое значение будет на выходе?

  • A: Lydia
  • B: Sarah
  • C: undefined
  • D: ReferenceError

Ответ

Каждая функция имеет свой собственный контекст исполнения (или область действия). Функция getName сначала ищет в своем собственном контексте (области действия), чтобы увидеть, содержит ли она переменную name , к которой мы пытаемся получить доступ. В этом случае функция getName содержит собственную переменную name : мы объявляем переменную name с ключевым словом let и значением ‘Sarah’ .

Переменные с ключевым словом let (и const ) поднимаются в начало функции, в отличие от var , которые не инициализируется. Они недоступны до того, как мы объявим (инициализируем) их строку. Это называется «временной мертвой зоной». Когда мы пытаемся получить доступ к переменным до их объявления, JavaScript выдает ReferenceError .

Если бы мы не объявили переменную name в функции getName , движок javascript посмотрел бы вниз по цепочки области действия. Внешняя область имеет переменную с именем name со значением Lydia . В этом случае он бы записал «Лидию».

112. Какое значение будет на выходе?

  • A: a and a
  • B: a and undefined
  • C: [‘a’, ‘b’, ‘c’] and a
  • D: a and [‘a’, ‘b’, ‘c’]

Ответ

Используя ключевое слово yield , мы получаем значения в функции генератора. С помощью ключевого слова yield* мы можем получить значения из другой функции-генератора или итерируемого объекта (например, массива).

В generatorOne мы получаем весь массив [‘ a ‘,’ b ‘,’ c ‘] , используя ключевое слово yield . Значение свойства value для объекта, возвращаемого методом next для one ( one.next().value ), равно всему массиву [‘a’, ‘b’, ‘c’] .

В файле generatorTwo мы используем ключевое слово yield* . Это означает, что первое полученное значение two равно первому полученному значению в итераторе. Итератор — это массив [‘a’, ‘b’, ‘c’] . Первым полученным значением является a , поэтому в первый раз, когда мы вызываем two.next().value , возвращается a .

113. Какое значение будет на выходе?

  • A: I love to program
  • B: undefined to program
  • C: $ <(x =>x)(‘I love’) to program
  • D: TypeError

Ответ

Выражения внутри литералов шаблона расчитываются первыми. Это означает, что строка будет содержать возвращаемое значение выражения, в данном случае немедленно исполняемую функцию (x => x)(‘I love’) . Мы передаем значение ‘I love’ в качестве аргумента стрелочной функции x => x . x равно ‘I love’ , которое и возвращается. Это приводит к I love to program .

114. Что произойдет?

  • A: обратный вызов setInterval не будет вызван
  • B: обратный вызов setInterval будет вызван один раз
  • C: обратный вызов setInterval будет вызываться каждую секунду
  • D: мы никогда не вызовем config.alert() , т.к. config равно null

Ответ

Обычно, когда мы устанавливаем объекты равными null , эти объекты получают метку собрано в мусор, так как больше нет ссылок на этот объект. Однако, поскольку функция обратного вызова в setInterval является стрелочной функцией стрелки (таким образом, привязанной к объекту config ), функция обратного вызова все еще содержит ссылку на объект config . Пока есть ссылка, объект не будет собран в мусор. Поскольку сборщик мусора не отрабатывает, функция обратного вызова setInterval будет по-прежнему вызываться каждые 1000 мс (1с).

115. Какие методы вернут значение ‘Hello world!’ ?

  • A: 1
  • B: 2
  • C: 2 и 3
  • D: Каждый из них

Ответ

При добавлении пары ключ/значение с использованием метода set имя ключа будет равно значению первого аргумента, переданного в функцию set , а значением будет второй аргумент, переданный в функцию set . В данном случае ключом является функция () => ‘greeting’ и значение ‘Hello world’ . myMap теперь это < () =>‘greeting’ => ‘Hello world!’ > .

1 неверно, поскольку ключ не ‘greeting’ , а () => ‘greeting’ . 3 неверно, так как мы создаем новую функцию, передавая ее в качестве параметра методу get . Объект взаимодействует со ссылкой. Функции — это объекты, поэтому две функции никогда не бывают строго равными, даже если они идентичны: они имеют ссылки на разные места в памяти.

116. Какое значение будет на выходе?

  • A:
  • B:
  • C:
  • D:

Ответ

Функции changeAge и changeAgeAndName имеют параметр по умолчанию, а именно вновь созданный объект < . person >. Этот объект имеет копии всех ключей/значений объекта person .

Сначала мы вызываем функцию changeAge и передаем объект person в качестве аргумента. Эта функция увеличивает значение свойства age на 1. person теперь .

Затем мы вызываем функцию changeAgeAndName , однако мы не передаем параметр. Вместо этого значение x равно новому объекту: < . person >. Поскольку это новый объект, он не влияет на значения свойств объекта person . person по-прежнему равен .

JavaScript — Функции. Оператор return

Статья, в которой рассмотрим, что такое функция, а также традиционный (классический) вариант работы с ней. Кроме этого, разберем, что такое аргументы (параметры) функции и оператор return.

Что такое функция?

Функция — это некоторый набор инструкций , которому можно дать имя , а затем обратиться к нему по этому имени из любого места программы.

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

Как организовать выполнение некоторой задачи в JavaScript с использованием функций? Чтобы это выполнить обычно поступают так:

  • разбивают задачу на составные части (подзадачи);
  • подзадачи оформляют через функции;
  • разрабатывают основной код с использованием вызова созданных функций.

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

Объявление и вызов функции

Операции с функцией в JavaScript можно разделить на 2 шага:

  • объявление (создание) функции.
  • вызов (выполнение) этой функции.

Объявление функции. Создание функции в JavaScript начинается с написания ключевого слова function , далее указывается имя функции, затем в круглых скобка х при необходимости перечисляются параметры , после этого указываются инструкции , которые заключаются в фигурные скобки .

JavaScript — Синтаксис объявления функции

Функции такого вида в JavaScript называются function declaration statement . Кроме этого вида в JavaScript ещё различают функции function definition expression и arrow function expression .

Составление имени функции выполняется по тем же правилам, что и имя переменной. Т.е. оно может содержать буквы, цифры (0-9), знаки «$» и «_». В качестве букв рекомендуется использовать только буквы английского алфавита (a-z, A-Z). Имя функции, также как и имя переменной не может начинаться с цифры.

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

Набор инструкций , заключенный в фигурные скобки — это код функции , который будет выполнен при её вызове .

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

JavaScript — Синтаксис вызова функции

Является ли функция в JavaScript объектом?

Функции в JavaScript являются объектами. В JavaScript вообще всё является объектами, кроме шести примитивных типов данных. А если функция является объектом, то ссылку на неё можно сохранить в переменную.

После этого вызвать функцию можно будет так:

Параметры и аргументы функции

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

Параметры функции – это один из способов в JavaScript, посредством которого можно обратиться к аргументам внутри функции. Описываются параметры функции на этапе её объявления в круглых скобках.

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

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

Например , вызовем функцию из примера, приведённого выше, без указания одного и двух параметров:

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

Другой способ обратиться к аргументам внутри функции – это использовать специальный объект arguments . Доступ к аргументам через arguments выполняется точно также как к элементам обычного массива, т.е. по их порядковым номерам. Таким образом, argument[0] — позволит получить первый аргумент, arguments[1] – второй аргумент и т.д.

Основное отличие между этими способами заключается в том, что первый из них позволяет обратиться только к тем аргументам, которым на этапе объявления функции были дали имена. Второй же способ позволяет получить значение любого аргумента, даже если у него нет имени (по порядковому номеру). Это возможность языка JavaScript позволяет создавать универсальные гибкие функции.

Кроме получения аргументов, объект arguments позволяет также узнать их количество. Выполняется это с помощью свойства length.

Перебрать аргументы , переданные функции, можно, например, с помощью цикла for или for. of .

Функция, выводящая в консоль все переданные ей аргументы и их количество:

Функция, выполняющая сложение все переданных ей аргументов (их количество заранее неизвестно):

В результате, посредством объекта arguments можно реализовать в теле функции:

  • проверку количества переданных аргументов;
  • обработку какого угодного количества параметров.

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

Значение параметров по умолчанию

Начиная с версии ECMAScript 2015 (6) параметру функции можно задать значение, которое он будет иметь по умолчанию.

Например , установим параметру «color» значение по умолчанию, равное «#009688»:

До ECMAScript 2015 задать параметру значение по умолчанию можно, например, было так:

Оставшиеся параметры (rest parameters)

Если при вызове функции ей передать аргументов больше, чем у неё есть параметров, то получить оставшиеся можно с помощью, так называемых оставшихся параметров (rest patameters) . Данная возможность в языке появилась, начиная с ECMAScript 2015.

Оператор return

Оператор return предназначен для возвращения значения или результата вычисления выражения текущей функции. Значение или выражение должно быть отделено от return посредством пробела. Кроме этого, оператор return прекращает выполнение функции, т.е. все инструкции, идущие после него, исполнены не будут.

Функция в JavaScript всегда возвращает результат в вне зависимости от того, используется ли оператор return или нет.

JavaScript — Функция с проверкой параметров

Функция в JavaScript в результате своего выполнения всегда возвращает результат, даже если он явно не определён с помощью оператора return. Этот результат значение undefined.

JavaScript — Получить значение у функции, которая ничего не возвращает

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

Перегрузка функций в JavaScript

Перегрузка функций в программировании – это возможность объявлять несколько функций с одинаковыми именами в одной области видимости. Отличаются такие функции друг от друга типом и числом аргументов. Каждая функция имеет свою программную логику. Используется перегрузка функций для того, чтобы с помощью одного имени функции можно было выполнять близкие действия.

Язык JavaScript не поддерживает перегрузку функций в том виде, как это реализовано, например, в Си подобных языках. Т.е. в JavaScript нельзя создать несколько функций с одинаковыми именами, находящихся в одной области видимости.

Подобную функциональность можно реализовать в JavaScript используя следующие действия:

  • Для того чтобы проверить передан аргумент или нет, используйте условие с проверкой его значения на undefined .
  • Для проверки количества переданных аргументов функции используйте свойство объекта arguments length .
  • Чтобы узнать тип переданного значения аргумента используйте операторы typeof или instanceof .
  • Для работы с переменным числом аргументов, используйте объект arguments .
  • Начиная с версии ECMAScript6, Вы можете указывать значения по умолчанию для аргументов.

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

Произведём некоторые изменения в вышепредставленном коде. А именно, укажем для второго параметра значение по умолчанию:

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

Рекурсия

Рекурсия – это вызов внутри тела некоторой функции самой себя.

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

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

Что такое встроенные (стандартные) функции?

В JavaScript имеется огромный набор встроенных (стандартных) функций. Данные функции уже описаны в самом движке браузера. Практически все они являются методами того или иного объекта.

Например, для того чтобы вызвать встроенную функцию (метод) alert, её не надо предварительно объявлять. Она уже описана в браузере. Вызов метода alert осуществляется посредством указания имени, круглых скобок и аргумента внутри них. Данный метод предназначен для вывода сообщения на экран в форме диалогового окна. Текстовое сообщение берётся из значения параметра данной функции.

Цукерберг рекомендует:  Mysql - mysql для Андрей Косинцев,
Понравилась статья? Поделиться с друзьями:
Все языки программирования для начинающих