function object - garevna/js-course GitHub Wiki

🎓 Объект function

⤵️
▶️ arguments
▶️ prototype
📋 ECMAScript® 2016 Language Specification:
☝️ Функция является вызываемым объектом
☝️ Функция, связанная с объектом через свойство, называется методом
▶️ Контекст выполнения
     ▶️ Lexical Environment
     ▶️ hoisting
     ▶️ Область видимости
     ▶️ this
▶️ Контекст вызова

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

У функции 🚑 есть "контекст исполнения":

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

Все это функция 🚑 возит с собой

В момент вызова у функции 🚑 появляется контекст вызова:

🏠

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

:neckbeard:

конкретный больной с конкретными симптомами, 
возрастом, историей болезни, характером и т.д.

🎓 КОНТЕКСТ ВЫЗОВА

⤴️ ⤵️

Контекст вызова - это объект

Обычно имя этого объекта стоит перед именем функции, и отделено от него точкой

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

Исключение составляют функции, контекст вызова которых установлен с помощью метода bind ()

⚠️ Отсюда следует, что все функции JS являются методами

Если объект ( "хозяин" метода ) не указан, подразумевается глобальный объект

☕ 1

🎓 ИНКАПСУЛЯЦИЯ

Таким образом, функция - это "капсула" со своим содержимым

Содержимое "капсулы" недоступно из контекста вызова

( посторонние не могут использовать материалы, инструменты и аппараты 🚑 )

🎓 this

Ключевое слово this - это ссылка на объект, в контексте которого вызвана функция

☕ Например, для функции 🚑

 this.адрес
 this.этаж
 this.квартира
 this.больной.имя
 this.больной.возраст
 this.больной.симптомы
 ...

Если бы не this, вряд ли функция могла бы помочь "больному" 😉

✏️ Сигнатура функции

⤴️ ⤵️

Сигнатура функции - это ее имя + список формальных параметров

Формальные параметры функции - это имена переменных, перечисленные в круглых скобках при объявлении функции

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

Если:

:point_up_2: функции будет передано аргументов больше числа формальных параметров, то лишние аргументы будут отброшены

:point_up_2: функции будет передано аргументов меньше числа формальных параметров, то недостающие аргументы получат значение undefined

🎓 Объект arguments

⤴️ ⤵️

Функции JavaScript имеют встроенный объект arguments

У него есть свойство length, как у массива

Его элементы доступны по индексу, как и элементы массива

⚠️ Однако это не массив

Поэтому к нему нельзя применить методы работы с массивами ( push, pop и т.д. )

Его можно преобразовать в обычный массив с помощью метода Array.from

var args = Array.from ( arguments )

В объекте arguments находятся все аргументы, переданные функции при ее вызове

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

☕ Например:

function testArguments () {
    for ( var i = 0;  i < arguments.length;  i++ ) {
        console.log ( `[ ${ ( i + " ]" ).padEnd ( 10 ) } ${ arguments [ i ] }` )
    }
}

testArguments ( 27, false, "Fill", [ 7, 4, 5 ], null )

✏️ arguments.callee

⤴️ ⤵️

У объекта arguments есть свойство arguments.callee -

ссылка на выполняемую функцию ( функцию-"хозяина" объекта arguments )

function testArguments () {
        console.log ( arguments.callee )
}

testArguments ( 5, false )

В свойстве arguments.callee находится ссылка на саму функцию testArguments

☕ 2 ☕ 3 ☕ 4 ☕ 5

🎓 КОНТЕКСТ ИСПОЛНЕНИЯ

⤴️ ⤵️
Когда происходит вызов функции, она активируется
Ей нужно где-то безопасно "разместить" 
свои данные, с которыми она будет работать

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

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

⚠️ Контекст выполнения создается каждый раз, когда происходит вызов функции

Что же будет в этом контексте?

✅ При вызове функции создается объект, содержащий все необходимые переменные

Этот объект в спецификации языка называется LexicalEnvironment

В этом объекте будут храниться полученные аргументы и все переменные функции

поэтому его еще называют объектом переменных или объектом активации

Когда функция завершит работу, объект LexicalEnvironment будет удален из памяти

✅ Однако функция может использовать какие-то переменные, которых нет в ее LexicalEnvironment

Они являются внешними, и находятся в другом контексте

Но они доступны функции

Функция "видит" их, поэтому они находятся в ее "области видимости"

⚠️ Область видимости - важная часть контекста выполнения

⚠️ Каждый вызов функции приводит к созданию нового контекста выполнения

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

✅ сразу после вызова функции, 
    но до начала выполнения кода
✅ на этапе выполнения кода

При каждом возврате ( return ) происходит выход из контекста выполнения

Пока выполнение функции не завершено, ее контекст будет активным

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

( очередь: последним пришел - первым ушел )

Верхним в этом стеке всегда будет текущий контекст исполнения

✏️ Lexical Environment

⤴️ ⤵️

Объект активации ( Lexical Environment ) содержит аргументы функции и все объявленные внутри функции переменные ( включая функции )

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

⚠️ Получить доступ к объекту активации невозможно

✏️ hoisting

⤴️ ⤵️

После вызова функции:

1️⃣ В первую очередь формируется контекст исполнения:

  • создается объект переменных ( или объект активации ),
  • определяется область видимости
  • устанавливается значение this

2️⃣ Затем внутренним переменным присваиваются значения, код интерпретируется и выполняется

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

⚠️ А вот присвоение переменным значений происходит, когда код начинает выполняться

Это приводит к "поднятию" ( hoisting ) объявлений переменных и функций

☕ 1 ☕ 2

✏️ Область видимости

⤴️ ⤵️

Область видимости ( scope ) ограничивает действие идентификаторов переменных и функций

Представьте себе двух человек по имени Саша:
👨‍💼 парня и 🙎 девушку

Есть две комнаты, 
и парень Саша  👨‍💼 находится в первой комнате, 
а девушка Саша 🙎 - во второй

В каждой комнате есть наблюдатель

Если мы спросим наблюдателя из первой комнаты: 
"Кем является Саша?", 
то он ответит: "Парень" 👨‍💼

Зададим аналогичный вопрос наблюдателю из второй комнаты, 
и получим ответ: "Девушка" 🙎

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

Однако область видимости вложенных функций 
будет несколько иной

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

Наблюдатель в коробке 2 будет видеть 
не только содержимое коробки 2, 
но и содержимое коробки 1 
и комнаты, 
внутри которой находятся все коробки

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

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

⚠️ Все доступные ей чужие "шкафчики" 
представляют собой  
📌 цепочку областей видимости функции,
которая является частью 
ее 📌 контекста выполнения
☕ 3 ☕ 4 ☕ 5

✏️ this

⤴️ ⤵️

this - это еще одна составляющая контекста исполнения функции

this является ссылкой на контекст вызова функции

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

☕ 6

function func () {
   console.log ( this )
}

при вызове функции func () в консоль будет выведен объект window

Внутри функции func () this указывает на объект window

☕ 7

function func () {
   child ()
   function child () {
      console.log ( 'child this: ', this )
   }
}

func ()  // window

☕ 8

⤴️ ⤵️

Если же функция является методом объекта, то ее контекстом вызова будет этот объект

var human = {
    name: "Ivan",
    say: function () {
        console.log ( 'this: ', this )
    }
}

human.say () // будет выведен объект  human

☕ 9

Теперь посмотрим на функцию как на объект

function say () {
   console.log ( 'function say: this: ', this )
}
function girl () {
   console.log ( 'function girl: this: ', this )
}

Добавим функции girl свойство say и вызовем функцию girl и ее свойство say:

girl.say = say
girl.say ()     //  girl
girl ()         // window

🎓 prototype

  • Функцию как объект нельзя вывести с помощью метода console.log
  • Для этой цели следует использовать метод console.dir
function sample () {}

console.dir ( sample )

В консоли мы получим следующую картинку:

▼ ƒ sample()
      arguments: null
      caller: null
      length: 0
      name: "sample"
    ▼ prototype:
        ▶ constructor: ƒ sample()
        ▶ __proto__: Object
    ▶ __proto__: ƒ ()
      [[FunctionLocation]]: VM476:1
    ▼ [[Scopes]]: Scopes[1]
        ▶ 0: Global {type: "global", name: "", object: Window}

Обратите внимание на свойство prototype, которое есть только у функций

  • это объект
  • в этом объекте есть свойство constructor
  • свойство constructor - это ссылка на саму функцию sample()

Обратите также внимание на свойство __proto__, которое мы разберем далее

  • это ссылка на объект, от которого функция унаследовала свои свойства и методы
  • любая функция создается встроенным нативным объектом ( конструктором ) Function ()
  • это свидетельствует о том, что функция - это объект
  • свойство constructor в __proto__ - это ссылка на Function ()

[[FunctionLocation]] и [[Scopes]] добавляет Chrome DevTools для целей отладки


🔗 w3schools

⤴️

⚠️ **GitHub.com Fallback** ⚠️