Объясните, зачем нужна анонимные самовызов. функции и замыкания?
Засорять глобальную область видимости нехорошо, потому что сложно следить, чтобы эти имена не пересекались в разных файлах, не использовались и не перезаписывались там, где не нужно. Например, если нужно вывести алертом сумму двух чисел numberOne и numberTwo:// глобальная функция add складывает все элементы массива
function add(arr) {
  return arr.reduce(function(a, b) {return a + b})
}

(function(a, b) {
  // локальная функция add складывает два числа
  function add(a, b) {
    return a + b
  }

  var sum = add(a, b)

  alert(sum)
})(numberOne, numberTwo)
Этот пример, конечно, искусственный (потому что на самом деле alert(numberOne + numberTwo)), но если заменить сложение и алерт на какие-то более-менее объёмные вычисления, то тот факт, что мы не перезаписываем глобальные функции (как в примере было бы с функцией add, если бы мы не обернули код в анонимную функцию), не засоряем глобальную область видимости счётчиками циклов и т. д., может предотвратить некоторые ошибки.
На счёт замыканий -- например, нам нужно написать функцию, которая принимает ID HTML элемента и строку и добавляет ему event listener, который при нажатии на элемент алертит эту строку:function foo(id, msg) {
  document.getElementById(id).addEventListener("click", function() {
    alert(msg)
  }
}
Здесь функция, которую мы передаём в addEventListener, и которая будет выполнятся при нажатии на элемент, берёт значение переменной msg из области видимости внешней функции -- это и есть замыкание.
Ещё один пример с замыканием:function add(a) {
  return function(b) {
    return a + b
  }
}

add(5)(6)  // 11
Возвращаемая функция берёт значение переменной a из области видимости внешней функции.
Чтобы понять, зачем нужны замыкания, попробуйте написать на JS что-либо более-менее серьезное без них.
IIFE используются в основном для предотвращения уплывания объявляемых в файле переменных в глобальную область видимости.