Как выполнить перегрузку функций с помощью оператора typeof

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

Например, при вызове с помощью строкового селектора он просто возвращает элементы, соответствующие этому выбору.

$("#id")
//selects the element matching that id
$(".class-name")
//selects the elements matching that class

При вызове со строкой, содержащей тег, функция jQuery создает новый элемент.

$("<div>")

При вызове с функцией он запускает функцию при загрузке DOM.

$(function() {
  //run on load
});

Нет поддержки перегрузки функций

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

function sum(a, b){
  return a + b;
}
function sum(a, b, c){
  return a + b + c;
}
console.log(sum(1, 2));
//NaN

В этом примере второе определение функции sum переопределяет первое. Функция sum теперь ожидает трех параметров и вызывается с двумя аргументами.

Создание «перегруженной» функции

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

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

  • выбирает элемент при вызове с помощью селектора CSS
  • создает элемент HTML при вызове с тегом HTML
  • вызывает функцию, когда документ загружается, если вызывается с функцией

Вызов обратного вызова

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

Утилита document.addEventListener позволяет прослушивать событие DOMContentLoaded.

document.addEventListener("DOMContentLoaded", function(){
  console.log("document loaded")
});

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

function $(arg){
  if (typeof arg === "function"){
    document.addEventListener("DOMContentLoaded", arg);
  }
}

Вот как мы можем использовать функцию полезности на этом этапе.

$(function(){ 
  console.log('document loaded');
});

Выбор элемента

Далее мы добавим поведение для выбора элемента.

Утилита document.querySelector выбирает элемент из DOM.

const selector = "#element";
const element = document.querySelector(selector);

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

function $(arg){
  if (typeof arg === "function"){
    document.addEventListener("DOMContentLoaded", arg);
  }
  if (typeof arg === "string"){
    return document.querySelector(arg);
  }
}

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

$(function(){ 
  const div = $("#div1");
  console.log(div)
})

Создание элемента

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

document.createElement позволяет создавать элемент DOM.

cont btn = document.createElement("button");

Мы определяем тег по наличию символа <.

function $(arg){
  if (typeof arg === "function"){
    document.addEventListener("DOMContentLoaded", arg);
  }
  
  if (typeof arg === "string" && arg.includes("<")){
    const tag = arg.replace("<", "").replace(">", "")
    return document.createElement(tag);
  }
  
  if (typeof arg === "string"){
    return document.querySelector(arg);
  }
}

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

$(function(){ 
  const div = $("#element");
  
  const button = $("<button>");
  button.innerText = "Click!";
  
  div.appendChild(button);
})

Спасибо за чтение.