Способ создания .hide() и .show() в обычном ванильном Javascript

Полностью избегая jQuery, сегодня я решил попробовать сделать что-то вроде:

$('#myDiv').hide();

И цель будет состоять в том, чтобы применить .style.display = 'none' к #myDiv.

Итак, мы узнаем, что следующий селектор немного похож на jQuery:

var $ = s => document.querySelectorAll.bind(document)(s).length > 1 ?
  document.querySelectorAll.bind(document)(s) : document.querySelector.bind(document)(s);

Просто будьте осторожны при его использовании, потому что он может возвращать несколько элементов, из которых вам может понадобиться использовать синтаксис .forEach(function(el,i){el.doSomething();});.

Итак, я попытался создать простую функцию $(...).hide(), например:

$.__proto__.hide = function(){this.forEach(function(el,i){el.style.display='none';});};

К сожалению, __proto__ теперь устарела, и даже если вы проигнорируете это, вышеизложенное не будет работать, если вы не сделаете что-то вроде этого:

$('#myDIV').__proto__.hide = function(){this.forEach(function(el,i){el.style.display='none';});};

Каков метод расширения моего объекта $ с помощью функции .hide() с использованием простого ванильного Javascript?

Есть множество хороших статей, которые можно найти в Интернете по запросу «как написать свой собственный jquery» или что-то в этом роде. Этот, кажется, хорошо охватывает основы: gomakethings.com/…

Scott Sauyet 18.12.2020 17:53

Смотрите здесь: youmightnotneedjquery.com

AbsoluteBeginner 18.12.2020 17:56
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Раскрытие чувствительных данных
Раскрытие чувствительных данных
Все внешние компоненты, рассмотренные здесь до сих пор, взаимодействуют с клиентской стороной. Однако, если они подвергаются атаке, они не...
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Руководство ChatGPT по продаже мини JS-файлов
Руководство ChatGPT по продаже мини JS-файлов
JS-файл - это файл, содержащий код JavaScript. JavaScript - это язык программирования, который в основном используется для добавления интерактивности...
0
2
92
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

В основном у вас есть два варианта:

  1. Используйте свой собственный объект, как это делает jQuery, или

  2. Расширьте встроенный прототип.

  3. Расширяйте каждый отдельный объект результата по мере его возврата; см. ответ 3limin4t0r

Я бы, вероятно, использовал подход № 1, возможно, расширив Array (или используя массив через композицию).

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

В вашем случае, если ваша функция $ возвращает результат querySelectorAll, она возвращает NodeList, и вы можете расширить NodeList.prototype. При расширении прототипа всегда используйте Object.defineProperty (или аналогичный) для определения неперечислимого свойства. Например:

Object.defineProperty(NodeList.prototype, "hide", {
    value() {
        this.forEach(/*...*/);
        return this;
    },
    writable: true,
    configurable: true
});

Живой пример:

Object.defineProperty(NodeList.prototype, "hide", {
    value() {
        // This isn't a great "hide", it's just for
        // the purposes of showing the plumbing
        this.forEach(el => el.style.display = "none");
        return this;
    },
    writable: true,
    configurable: true
});

const $ = selector => document.querySelectorAll(selector);

setTimeout(() => {
    $(".a").hide();
    console.info("Hid .a elements");
}, 800);
<div class = "a">a</div>
<div class = "b">b</div>
<div class = "c">c</div>

К сожалению, __proto__ больше не поддерживается.

Это правда, но Object.getPrototypeOf не является, просто свойством доступа __proto__ (оно было добавлено в спецификацию только для обратной совместимости).

Ответ принят как подходящий

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

class ElementsHelper {
  constructor(elements) {
    this.elements = elements;
  }

  // helper to simplify iterating `this.elements` and returning `this`
  forEach(fn) {
    this.elements.forEach(fn);
    return this;
  }

  hide() {
    return this.forEach(element => element.style.display = "none");
  }

  click(fn) {
    return this.forEach(element => element.addEventListener("click", fn));
  }

}

function $(selector) {
  return new ElementsHelper(document.querySelectorAll(selector));
}

С вышеизложенным теперь вы можете сделать:

$('#myDiv').hide();

Не могу поверить, что я исключил этот вариант из своего списка. :-) Это была очень длинная неделя.

T.J. Crowder 18.12.2020 18:21

Другие вопросы по теме