Tipos de funções

Funções Declarativas

A nomeação é obrigatória.
Também conhecidas como Regular Functions.
A sintaxe básica é: function fn(){}

                            function hello() {
                                console.log("Hello World!");
                            }
                                
                            function sum(a, b) {
                                console.log(`${a} + ${b} = ${a + b}`);
                            }
                            
                            function sub(a, b) {
                                return a - b;
                            }
                        

Expressões de Funções

São funções que representam expressões.
A nomeação é opcional.
Quando não há nomeação, chamamos de função anônima.
Nunca são invocadas diretamente, sempre são atribuídas, porque uma variável pode armazenar uma função.

                            var fn1 = function fnNomeada() {
                                console.log('função nomeada');
                            };
                            
                            var fn2 = function () {
                                console.log('função anônima');
                            };
                        

Arrow Functions - Expressões de Funções de Sintaxe Curta

Funções Anônimas

Sempre serão expressões de funções.
Pode ser uma Regular Function ou Arrow Function.
Por serem expressões de funções, sempre serão atribuídas, nuncas invocadas diretamente.

                            // Regular Function
                            var fn = function () { console.log('Hello World'); };

                            // Arrow Function
                            var fn = () => console.log('Hello World');
                        

Funções Construtoras (Factoring Functions)

São funções que geram objetos.
Sempre serão Funções declarativas ou Funções Regulares Nomeadas, porque precisa existir o this.
Por convenção, a primeira letra do nome deve ser maiúscula.

                            function Car(){
                                this.marca = 'Fiat';
                                this.modelo = 'Uno';
                            }
                            console.log(new Car());  // Car {marca: 'Fiat', modelo: 'Uno'}
                        
                            function Dog(name, age){
                                return {
                                    name,
                                    age
                                }
                            }
                            const pintcher = new Dog('Hulk', 4);
                            console.log(pintcher);  // {name: 'Hulk', age: 4}
                        

Funções IIFE (Immediately Invoked Function Expression)

São expressões de funções executadas imediatamente após sua declaração.
Podem ser anônimas ou nomeadas.
A declaração da função é envolvida entre parênteses.
A execução da função é realizada com parênteses, logo após a declaração.
Ou seja:
Primeiro parênteses é a declaração da função.
Segundo parênteses é a execução da função. Representa a sua chamada e é por aqui que podemos enviar argumentos.
Exemplo com duas formas de escrever, mas mesmo efeito:

                                // Segundo parênteses fora do primeiro parênteses
                                    (function fn(){
                                        alert('Hello world!');
                                    })(); 
                            
                                // Segundo parênteses dentro do primeiro parênteses
                                    (function fn(){
                                        alert('Hello world!');
                                    }());
                            
Exemplo com parâmetros:

                                (function (arg){
                                    alert(arg);
                                }
                                )('Hello world!');
                            
Exemplo, simulação de acesso privado: O escopo é usado para criar um fechamento (closure) e impedir que dados sejam acessados dentro desse escopo fechado.

                                const fn = (
                                    function () {
                                        const password = 1337;
                                        return function () {
                                            console.log(password);
                                        }
                                    }
                                )();
                            
Mantém a referência para o escopo pai, como é o caso de toda função aninhada.
Agora, temos em fn() um estado mutável privado que não pode ser acessado de fora da função. No entanto, quando realizamos o console.log por dentro da função retornada, conseguimos acessar o valor de password.

OBS: Deixar essas variáveis em escopos fechados não tem vantagens apenas na segurança dos dados. Se menos variáveis são criadas no escopo global, reduzimos o ruído e a chance de conflito entre seus nomes.

Callback

É uma função passada como argumento para outra função.
Fornece maior controle sobre a ordem das chamadas.

                            const calc = function(operation, num1, num2){
                                return operation(num1, num2);
                            }
                            const sum = function(num1, num2){
                                return num1 + num2;
                            }
                            const sub = function(num1, num2){
                                return num1 - num2;
                            }
                            const resultSum = calc(sum, 10, 5);
                            const resultSub = calc(sub, 10, 5);
                            console.log(resultSum);
                            console.log(resultSub);