КОДЕКС

Часть того, почему я считаю React мусором

С реальными примерами!

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

React, Vue, Angular и их аналог для меня не имеют смысла. ЕСЛИ (большое, если) они - или могут - использоваться на стороне сервера, они не что иное, как раздутая чушь кода, добавляющая дополнительные шаги нулевое значение. Они не делают ничего на стороне сервера, что функции / методы со строками шаблонов не могли бы сделать чище / эффективнее. При использовании на стороне клиента для обычных вещей, таких как тележки для покупок и контактные формы, они переворачивают птицу с точки зрения удобства использования и доступности, поскольку эти вещи не должны быть изначально написаны сценариями или, по крайней мере, иметь изящную деградацию. Что еще хуже, они «скрывают» фактическое взаимодействие с DOM и добавляют ненужную сложность.

Хотя, как некоторые отмечают, некоторых из этих проблем, безусловно, можно избежать - см. «Гэтсби» - это только делает вещи еще более бессмысленными, которые можно было бы сделать проще, чище и понятнее без фреймворков. На стороне сервера HTML кажется слишком сложным, поэтому они усложняют его еще больше. На стороне клиента это похоже на то, как если бы DOM обрабатывалась так же.

Одних только этих причин должно быть достаточно для отказа от их использования. Неважно, сколько слепо попугает пропаганду, которая не делает ее реальностью. Честно говоря - я знаю, если честно? Шокирует! - многие причины, по которым люди создают и поддерживают эти «рамки», в лучшем случае сводятся к дезинформации и недопониманию, а в худшем - к откровенной лжи!

Ложь

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

«Работа с Live DOM идет медленно!»

Bullcookies! Нет очевидного улучшения их памяти и обработки, тратя впустую «виртуальный DOM» и просто переходя прямо к действующему DOM. Во всяком случае, это медленнее, потому что им нужно «различать» изменения своих фрагментов документа с живым документом! Просто сделай кровавое изменение!

«Не храните данные в реальном DOM, это небезопасно»

100% фантастика. В конце концов вы собираетесь поместить его туда, и подключенные узлы в реальном времени или нет, не только не влияют на скорость, но и не создают никаких проблем с безопасностью.

«Модель DOM слишком сложна для нормальных людей»

По сравнению с запутанным спагетти-кодом, присущим React? ДЕЙСТВИТЕЛЬНО? Это просто дерево объектов. Я искренне думаю, что эти утверждения о том, что ванильный код настолько «сложен», проистекают из иррационального страха перед объектами, который внушают людям, которые говорят: «Ты слишком туп для этого».

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

Я мог бы довольно долго говорить о другой лжи, но все они сводятся к тому, чтобы по-разному утверждать, что выполнение большей работы с большим количеством кода более сложным образом каким-то волшебным образом «легче», или «проще», или «лучше». », Чем ванильные эквиваленты. Для меня это бессмысленный дым и зеркала, чтобы скрыть общее незнание HTML, CSS, JavaScript и того, для кого вообще существуют веб-сайты.

Докажите это!

Хорошо, тогда давайте воспользуемся двумя самыми «мясистыми» примерами из первых руководств и документации по Reacts: игра «Крестики-нолики» и калькулятор преобразования температуры. Как бы я ни говорил о React, это два отличных варианта в качестве примеров, учитывая, что они сочетают в себе логику, несговорчивость и хорошо подходят для работы только на стороне клиента, поскольку ни один из них не является «критически важным», как контактная форма или корзина для покупок. Последние две вещи никогда не должны НА 100% полагаться на JavaScript.

«Make» и другие функции библиотеки

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

Первая простая процедура называется «make». По функциям он похож на «создание» в React, за исключением того, что он может принимать структуры JSON в различных формах, чтобы «создавать» более крупные деревья DOM за один проход. Считайте, что это примерно эквивалентно тому, в что скомпилирован JSX. Мне не нравится JSX, потому что я предпочитаю, чтобы код, который я написал, был кодом, который был развернут, потому что тогда его легче изменять, отлаживать и поддерживать.

Может быть, это только я ... но развертывание кода, который не является тем, что вы написали, когда язык интерпретируется и исходный код доставляется, кажется довольно сумасшедшим. Наверное, один из авторов, почему мне тоже не нравятся LESS / SASS / SCSS.

function make(tagName, data) {
  var e = document.createElement(tagName);
  if (data) {
    if (
      data instanceof Array ||
      data instanceof Node ||
      ("object" !== typeof data)
    ) return makeAppend(e, data), e;
    if (data.append) makeAppend(e, data.append);
    if (data.attr) for (
      var [name, value] of Object.entries(data.attr)
    ) setAttribute(e, name, value);
    if (data.style) Object.assign(e.style, data.style);
    if (data.repeat) while (data.repeat[0]--) e.append(
      make(data.repeat[1], data.repeat[2])
    );
    if (data.parent) data.parent.append(e);
  }
  return e;
} // make

Вы передаете ему тег, который хотите создать, а затем либо массив дополнительных инструкций, которые передаются для создания дочерних элементов указанного элемента, либо объект, содержащий .append для добавления дочерних элементов таким же образом, .attr для назначения атрибутов,. style для установки стиля, .repeat для создания группы одних и тех же дочерних элементов и / или .parent, чтобы указать, под каким новым элементом должен быть создан.

Более надежная версия будет включать атрибут «размещение», указывающий, где он должен быть добавлен по отношению к родительскому элементу.

Например, если мы хотим сделать стандартный тест THEAD under table #, заполненный TR и правильно ограниченный TH:

make("thead", {
  append : [
    [ "tr", [
      [ "th", { scope : "col", append : "Item" } ],
      [ "th", { scope : "col", append : "Quntity" } ],
      [ "th", { scope : "col", append : "Unit Price" } ],
      [ "th", { scope : "col", append : "Total" } ]
    ] ]
  ],
  parent : documnt.getElementById("test")
] );

Довольно просто. Эта процедура «make» основана на двух других подпрограммах:

function makeAppend(e, data) {
  if (data instanceof Array) {
    for (var row of data) {
      e.append(row instanceof Array ? make(...row) : row);
    }
  } else e.append(data);
} // makeAppend
function setAttribute(e, name, value) {
  if (
    value instanceof Array ||
    ("object" == typeof value) ||
    ("function" == typeof value)
  ) e[name] = value;
  else e.setAttribute(name === "className" ? "class" : name, value);
} // safeSetAttr

makeAppend похож на Element.append, но он принимает массив того, что нужно добавить, и, если он обнаруживает массив в потоке данных, он вместо этого вызывает "make".

setAttribute является зеркалом Element.setAttribute, но без "проблем". Например, метод Element принимает только строки, которые могут быть неправильными, если вы хотите установить что-то вроде атрибута onEvent. Если данные являются объектом, массивом или функцией, нам нужно выполнить прямое присвоение. И наоборот, некоторые атрибуты могут испортиться, если вы назначите их напрямую, поэтому нам нужен обычный Element.setAttribute для любых значений, которые не относятся к этим типам. Я также добавляю className к классу, поскольку setAttribute для className не работает, и нет Element.className для SVG, XML или других элементов, отличных от HTML. На самом деле нам это не нужно, но все же хорошо быть безопасным для XML / SVG.

Последняя функция, которую я добавил, - это «очистка».

function purge(e, amt) {
  var dir = amt < 0 ? "firstChild" : "lastChild";
  amt = Math.abs(amt);
  while (amt--) e.removeChild(e[dir]);
} // purge

Что удаляет количество дочерних элементов «amt» с конца родительского элемента «e». Если вы скармливаете ему отрицательное число, он удалит их с самого начала.

Вкратце, это 80% + всего, что мне когда-либо понадобится во вспомогательных функциях для большинства вещей, которые я когда-либо делал в JS в наши дни.

Итак, приступим!

Крестики-нолики

Их оригинал:
https://codepen.io/gaearon/pen/gWWZgR?editors=0010

Моя перезапись:
https://codepen.io/jason-knight/pen/qBqwrwo

На мой взгляд, у оригинала есть «проблемы» как в нечеткости кода, так и в том, как он построен на DOM. Некоторые из этих проблем не имеют ничего общего с JavaScript, а просто указывают на то, что люди, создающие эти системы, не обладают квалификацией для написания единственной строчки HTML или CSS.

Такие, как «DIV for Nothing» .board-row в их сгенерированной разметке, их неспособность использовать FIELDSET в том, что, очевидно, является группой полей, моча по всему JSX с классами ни за что, весь мусор «состояния», который заканчивается отслеживание дополнительных данных в памяти, которые не только не нужно отслеживать, но и было бы быстрее / чище реализовать с помощью сброса данных и записи только оборотов. Даже использование пиксельных показателей в таблице стилей - гигантский средний палец к удобству использования и доступности - заставляет задуматься о том, обладают ли люди, СОЗДАВШИЕ эту систему, достаточной квалификацией, чтобы рассказывать людям, как использовать веб-технологии.

Хуже того, вы просто не видите фактическое значение, записываемое в действующую модель DOM, а это означает, что вы на 100% полагаетесь на их код, чтобы даже догадываться, правильно ли обновляются. Я знаю, что люди утверждают, что эта чушь о «состоянии» и виртуальном DOM чище или проще… Я просто не вижу этого.

Мы начинаем с объявления всех переменных, специфичных для отслеживания состояния игры. Если вас беспокоит так много глобальных объектов, 1) их код тоже делает это, 2) оберните его в IIFE или включите как модуль. Психологи «функционального программирования», писающие и стонущие о «побочных эффектах», могут сосать яйцо.

Как я уже говорил, если вы делаете это «специально», это не «побочный эффект». Есть только одна причина, по которой они выбрали этот термин для его описания, и он не имеет ничего общего с тем, что доступ к родительской области видимости является «злом». Программирование 101 - по крайней мере, когда я узнал об этом несколько десятилетий назад - внутренний масштаб - хорошо, внешний - плохой. Если это ДЕЙСТВИТЕЛЬНО вас беспокоит, сделайте все это объектно-ориентированным и потратите кучу кода, повсюду повторяя «это».

var
  lines = [
    [ 0, 1, 2 ],
    [ 3, 4, 5 ],
    [ 6, 7, 8 ],
    [ 0, 3, 6 ],
    [ 1, 4, 7 ],
    [ 2, 5, 8 ],
    [ 0, 4, 8 ],
    [ 2, 4, 6 ]
  ],
  player,
  squares = make('fieldset', {
    repeat : [ 9, "input", {
      attr : { onclick : squareClick, type : "button" },
    } ],
    attr : { id : "board" },
    parent : document.body,
  }).elements,
  turn,
  turnHistory = [],
  turnOL = make("ol"),
  txtPlayer = new Text(),
  txtTurn = new Text(),
  winner;

Предварительное объявление всех наших переменных в одном месте дает нам перекрестную ссылку, к которой мы можем легко перейти, чтобы узнать, что используется. Это что-то вроде парня из Pascal / Modula / Ada, которое я считаю значительно лучше этой бессмысленной и порождающей ошибки практики, когда люди просто позволяют людям объявлять переменные где угодно в середине логики кода. Когда я изучал программирование для чего-либо, кроме счетчиков для циклов, это был просто плохой код, даже если это норма в **** - показать, что опечатка, вызывающая утечку памяти, становится новой переменной, «какие *** переменные даже используются» такие языки, как C!

Важным моментом здесь является переменная squares, ссылка на набор полей # board.elements, которые будут нашими кнопками игрового поля. Я заполняю его 9 входными данными типа = "button", чтобы мы могли установить для него "значение", которое ведет себя так же, как textContent для кнопки. Это просто код без волос, которым легче манипулировать. Обратите внимание, что мы установили событие onclick как squareClick. Мы скоро к этому вернемся.

player, turn и winner отслеживают состояние игры. turnHistory должен быть понятным, как и turnOL. txtPlayer и txtTurn - это текстовые узлы, на которые мы сохраняем ссылки, прежде чем сохранять их в структуре нашей информации DIV.

Обратите внимание, что «new Text ()» - это новый способ выполнения «document.createTextNode». Функционально идентичен, просто работать с ним проще. Хотелось бы, чтобы ECMA предоставил Element конструктор!

Теперь, когда они у нас есть, мы можем создать информационный DIV, который будет содержать текущего игрока и список.

make('div', {
  append : [ txtTurn, " : ", txtPlayer, turnOL ],
  parent : document.body
});

Снова простая процедура make создает наш DIV, добавляет элементы, которые мы создали как переменные, вместе с “ : “ между текстом хода («Следующий игрок» или «Победитель») и игроком («X» или «O»).

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

function turnButton(append, onclick, value) {
  make("li", {
    append : [ [ "button", { attr : { onclick, value }, append } ] ],
    parent : turnOL
  });
} // turnButton

Снова используя make, чтобы добавить LI, кнопку внутри него и т. Д., И т. Д. Обратите внимание, что эти кнопки поворота также могут иметь установленное значение. Здесь помогает «кнопка», так как мы можем хранить значение (поворот) отдельно от его текста. Также обратите внимание, что, используя имена аргументов, которые соответствуют нашим назначениям объектов, нам не нужно говорить «onclick: onclick» или «value: value». Меня часто удивляет, сколько разработчиков JS не знают, что вы можете это сделать…

Нам также нужна функция «перезапуска», чтобы установить начальное состояние игры или вернуть игру в это состояние.

function restart() {
 for (var square of squares) square.value = "";
 txtPlayer.textContent = player = "X";
 winner = false;
 turn = 0;
 txtTurn.textContent = "Next Player";
} // restart

Очистите все квадраты, установите игрока и текст, показывающий текущего игрока, на «X», установите для победителя значение false, поверните 0 (ходов не будет) и установите текст инструкций на «Следующий игрок».

Таким образом, нашим следующим шагом в настройке будет добавление:

turnButton("Go To Game Start", restart);
restart();

Добавляем назад в начало и инициализируем состояние воспроизведения. Я делаю это отдельно от переменных запуска, чтобы мы не повторяли одно и то же дважды. Это тот случай, когда «игровой» объект имел бы больше смысла, но я стараюсь не усложнять.

Затем нам понадобится обработчик обратного вызова для всех этих событий щелчка на квадратах.

function squareClick(e) {
  e = e.currentTarget;
  if (winner || e.value) return;
  e.value = player;
  if (turnHistory.length > turn) {
    purge(turnOL, turnHistory.length - turn);
    turnHistory = turnHistory.slice(0, turn);
  }
  turnHistory.push(e);
  turn++;
  turnButton("Go to move " + turn, goToTurn, turn);
  calcWinner();
} // squareClick

Мы начинаем с захвата текущего элемента, так как нас не волнует само событие. Если у нас уже есть победитель или значение квадрата, на которое щелкнули мышью, установлено, прервитесь раньше. В противном случае текущий элемент устанавливается на текущего игрока («X» или «O»). Если история хода длиннее текущего хода, мы хотим удалить все эти кнопки «Перейти к перемещению», а также записи истории. Затем мы можем вставить этот элемент в историю поворотов, увеличить счетчик поворотов, а затем создать новый TurnButton LI / BUTTON. Наконец, проверьте, есть ли победитель.

Процедура проверки победителя:

function calcWinner() {
 for (var [a, b, c] of lines) if (
  (player == squares[a].value) &&
  (player == squares[b].value) &&
  (player == squares[c].value)
 ) {
  txtTurn.textContent = "Winner";
  return txtPlayer.textContent = winner = player;
 }
 if (turn == 9) {
  txtTurn.textContent = "Tie";
  txtPlayer.textContent = "Game Over";
 } else nextPlayer();
} // calcWinner

Он также довольно прост и имеет лучшее короткое замыкание, чем их.

  1. У меня нет внутри него «строк», которые добавляли бы накладные расходы на выполнение и память, которые не исправляет даже «const».
  2. По сравнению с player я могу реализовать более простые проверки с более быстрым прерыванием цикла.
  3. Используя for / of вместо цикла старой школы, я могу выполнять деструктурирование в цикле. Также не помогает то, что они используют здесь const, которая, если бы они были НАСТОЯЩИМИ константами, прервала бы цикл выполнения. На самом деле я не уверен, почему им разрешили / следует разрешить работать на этих основаниях ... но опять же, я также считаю, что let / const бесполезна / бессмысленна. Они вам нужны, у вас наверняка проблемы посерьезнее.
  4. При необходимости мы возвращаем победителя, в противном случае аннулируется, поскольку это значение по умолчанию. Необязательно return false; явно return false;, поскольку это одно из преимуществ нечеткого приведения типов и «правдивости». Прекратите бороться с тем, что JS пытается упростить!

Я также ловлю последний ход для соответствующего сообщения (что-то, чего они не делают), а также увеличиваю здесь игрока.

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

function goToTurn(e) {
  restart();
  for (var input of turnHistory) {
    input.value = player;
    if (++turn == e.currentTarget.value) break;
    nextPlayer();
  }
  calcWinner();
} // goToTurn

Сбросьте игровое поле, прокрутите историю, применяя каждый ход игроков к соответствующим квадратам, используя «nextPlayer» внутри цикла. Применяется во много раз быстрее, чем вся эта государственная чушь, несмотря на приложение «с нуля». Наконец, мы вызываем calcWinner , чтобы установить состояние выигрыша, если это необходимо.

nextPlayer функция очень проста:

function nextPlayer() {
 txtPlayer.textContent = player = player === "X" ? "O" : "X";
} // nextPlayer

В двух словах, это быстрое и грязное переписывание. Я бы, наверное, очистил его какими-то предметами и так далее, но даже если сравнивать с оригиналом, ну ...

Сравнение

Их исходное использование JSX составляет 3247 байт, но для четной работы он полагается на react.js. У меня 3 354 байта, но это не совсем корректное сравнение.

Почему это несправедливо? Во-первых, у меня есть комментарии к закрытию функций и разделам, но у них нет комментариев. Итак, если мы вычеркнем все комментарии? Его размер уменьшился до 3118 байт. Так что на самом деле все на 129 байт меньше ...

… либо это? Нет, это все равно несправедливо, потому что они могут использовать всю библиотеку fatass react.js. Так что, полагаясь на их библиотеку, вы сможете написать столько же кода, сколько и без нее! Код, в котором половина того, что на самом деле происходит, даже скрыта от вас!

Итак, чтобы уравнять правила игры, мы должны отказаться от моих вспомогательных функций, так же как мы не считаем response.js… и это сокращает нас до 1956 байт. Это примерно 60,2% всего кода для той же базовой функциональности ...

Извините за шрифт и качество изображения, оно уменьшено на 50% по сравнению с дисплеем 4k.

И глядя на источник двух рядом друг с другом, я знаю, с каким из них я бы предпочел работать, и это точно, как shine-ola, а не тот, который работает с React.

Калькулятор температуры

Этот гораздо более простой пример еще менее эффективен и менее продуман в реализации, полностью из-за того, как работает React. Я снова воспользуюсь той же вспомогательной библиотекой в ​​виде make, но для этого purge мне не нужен.

Их оригинал:
https://codepen.io/gaearon/pen/WZpxpz?editors=0010

Моя перезапись:
https://codepen.io/jason-knight/full/OJbGmoN

На этот раз их работа стала еще более неудачной с точки зрения того, что они создают, поскольку они используют FIELDSET и LEGEND для выполнения работы LABEL, даже не позаботившись о предоставлении надлежащего FIELDSET или LEGEND. Это первая чертова вещь, которую я исправил.

Но оттуда он идет еще быстрее. Весь этот мусор JSX - это мусор с раздутым кодом, из-за которого делать что-либо БОЛЕЕ сложнее. Хуже того, они жестко запрограммировали преобразования вместо настройки объекта с несколькими преобразованиями. Это как раз тот случай, когда объекты и массивы должны / должны использоваться для большей простоты и эффективности кода. Я имею в виду, черт возьми, посмотрите на спагетти только по Цельсию и Фаренгейту, имеющим таблицу поиска, функцию преобразования для каждого, жестко запрограммированные обработчики для каждого и бесконечную цепочку мусора «функционального программирования», которая ничего не делает, кроме добавления дополнительных накладных расходов на выполнение, одновременно нарушая вещи разбиваются на подразделы, которые не нужно разбивать. Для вещей, которые могут / должны быть обработаны одним обработчиком событий от шести до восьми строк и одним ссылочным объектом!

Поэтому первое, что я написал:

var
  scales = {
    celcius : {
      fahrenheit : (t) => 32 + t * 1.8,
      kelvin : (t) => 273.15 + t
    },
    fahrenheit : {
      celcius : (t) => (t - 32) / 1.8,
      kelvin : (t) => 273.15 + ((t - 32) / 1.8)
    },
    kelvin : {
      celcius : (t) => t - 273.15,
      fahrenheit : (t) => (t - 273.15) * 1.8 + 32
    }
  },

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

Вы хотите добавить еще одну температурную шкалу, просто создайте новый объект верхнего уровня, как я сделал с Кельвином, затем создайте вычисления, чтобы преобразовать его в другие типы как дочерние лямбды, а затем добавьте к ним соответствующие лямбды для преобразования друг друга. Легкий лимонный сок.

Затем я использую make для создания FIELDSET и создания текстового узла для подключения состояния.

  root = make("fieldset", {
    append : [ [ "legend", [
      "Enter a temperature in any field below for conversion"
    ] ] ],
    parent : document.body
  }),
  boilingText = new Text();

Теперь у нас есть правильная FIELDSET группировка, и мы больше не злоупотребляем LEGEND , предоставляя настоящую.

Чтобы внести различные данные на основе наших шкал…

function makeTempInput(name, parent) {
  Object.defineProperty(scales[name], "input", {
    value : make("input", {
      attr : {
        id : "tempCalc_" + name,
        name,
        oninput : onTempInput,
        pattern : "[-+]?[0-9]*[.,]?[0-9]+",
        type : "number"
      },
    })
  });
  make("label", {
    append : [ name, ["br"], scales[name].input, ["br"] ],
    parent
  });
} // makeTempInput

Я использую Object.defineProperty для создания элемента INPUT на весах. Я делаю это для того, чтобы его можно было прочитать, но не для перечисления / итерации. Таким образом, когда мы хотим перебрать видимые свойства объекта, ссылка на соответствующий ввод не будет мешать. Поскольку нам не нужна ссылка на метку, мы просто делаем это отдельно, добавляя некоторые разрывы строк для простого форматирования, так как нет причин тратить контейнеры уровня блока на каждую из них.

На самом деле, оглядываясь назад, мне не нужны эти идентификаторы. Что ж, сейчас я не вернусь и не сделаю заново скриншоты и другие развертывания.

Для тех, кто не может понять такую ​​простую вещь, как DOM, приведенное выше в основном делает то же самое, что:

<label>
  fahrenheit<br>
  <input
    id="temp_fahrenheit"
    name="fahrenheit"
    oninput="ontempinput();"
    pattern="[-+]?[0-9]*[.,]?[0-9]+"
    type="number"
  ><br>
</label>

Прикреплен к нашему «корню» FIELDSET прямо на DOM, но со ссылкой на INPUT добавлен в соответствующий подраздел scales.

Обратите внимание на использование type = ”number” и шаблона, который позволяет нам отключить проверку значения скрипта. В нем отсутствует паста, но на данный момент ее более чем достаточно. Вероятно, это несправедливое преимущество с моей стороны, поскольку кто знает, когда их пример обновлялся в последний раз. Тем не менее, спасибо W3C за одно из немногих полезных дополнений из HTML 5.

Затем мы можем просто вызвать его для каждого из наших scales.

for (var name in scales) makeTempInput(name, root);

Естественно нам понадобится обработчик oninput.

function onTempInput(event) {
  var input = event.currentTarget;
  for (
    var [name, method]
    of Object.entries(scales[input.name])
  ) scales[name].input.value = method(input.valueAsNumber);
  boilNoticeUpdate();
} // onTempInput

Мы получаем INPUT element, который инициировал событие, мы просматриваем все scales, связанные с этим INPUT, и выполняем связанные с ними методы на основе значения INPUT.

Также, используя HTMLInputElement.valueAsNumber, мы избегаем еще большей головной боли, связанной с тем, что люди заставляют туда вводить текст. Это относительно новое дополнение к свойствам модели DOM. Мне это нравится. Мне это очень нравится.

Затем проверяем на кипение:

function boilNoticeUpdate() {
 boilingText.textContent = scales.celcius.input.value >= 100 ? "" : "not";
} // boilNoticeUpdate

Изменение только одного маленького крошечного textNode, а не всей взорванной строки. Потому что да, вы можете настроить таргетинг на подразделы текста без узлов элемента, поскольку текстовые узлы также могут быть одноуровневыми и не сворачиваются автоматически. (если вы не сделаете что-то глупое, например innerHTML или textContent для родительского элемента)

И при запуске он вызывает boilNoticeUpdate, чтобы убедиться, что текст правильный. Firefox любит сохранять значения при обычных обновлениях, поэтому такие обновления статуса должны выполняться во время запуска.

… вот и все.

Сравнение

Оригинал на основе React занимает 2441 байт, в то время как мой переписанный - 2630 байт, но, опять же, это не равные условия. Не только на этот раз, учитывая вспомогательные функции и комментарии, у нас также есть поддержка Кельвина.

Удаление только комментариев уменьшает его до 2442, почти такого же размера. Удалите градусы Кельвина, просто изменив декларацию весов на:

  scales = {
    celcius : {
      fahrenheit : (t) => 32 + t * 1.8
    },
    fahrenheit : {
      celcius : (t) => (t - 32) / 1.8
    }
  },

… И он падает до 2262. Таким образом, даже с учетом накладных расходов пользовательской функции make и ее зависимых элементов, выполняющих примерно то же, что и response.js, на самом деле он на 179 байт меньше. Если мы удалим их для честного сравнения, так как в этом случае мы не учитываем сам response.js, мы получим всего 1243 байта! Это для всех намерений и целей ПОЛОВИНА КОДА!

Еще больше смеха, когда вы понимаете, что я использую полные названия температур, а не отдельные буквы. Таким образом, мне не нужна таблица преобразования. Хотите первую букву в верхнем регистре? Сделайте это в CSS!

Хотя мне бы очень помогло, если бы я запомнил первую букву «h» по Фаренгейту.

За этим легче следить, он более расширяемый / масштабируемый, поскольку преобразования не жестко запрограммированы, и поскольку мы убрали всю эту виртуальную DOM и ненужные сравнения, это более эффективно как с точки зрения использования памяти, так и с точки зрения времени выполнения!

Опять же, что бы вы предпочли сохранить?

Что еще более важно, с каким из них вы бы предпочли иметь дело, когда придет время добавить к нему больше температурных шкал? Вы знаете, о масштабируемости, о которой эти разработчики фреймворков постоянно трепещут?

Заключение

Методология Reacts в основном заставляет вас писать - если вы опускаете вспомогательные функции / библиотеки и сам response.js в любом из способов выполнения - напишите вдвое или больше кода, необходимого для выполнения работы. Кажется, это тоже увеличивается, поэтому как консультант по доступности и эффективности я постоянно сталкиваюсь с клиентами с мегабайтами сценариев на сайтах, где половина из них даже не нуждается в сценариях, а другая половина не имеет оправданий. более 48к кода. Мегабайты переворачивают килобайты!

И это мои цифры, мистер Скотт. Ака, посчитайте, сколько вам действительно нужно, а затем удвойте его.

… И мы даже не говорили о еще более крупном коде, который он фактически выводит на стороне клиента. Даже с вспомогательными функциями, которые выводят нас на тот же уровень функциональности, это почти такой же объем кода.

Как это проще, проще или лучше? Это абстракция ради абстракции. Конечно, я перескочил в глобальное пространство так, как никогда бы не сделал, но их примеры тоже, потому что это ПРИМЕРЫ.

Ни в коем случае форма или форма не являются их подходами лучше или проще, равно как и любые другие необоснованные необоснованные заявления людей об этих типах фреймворков. Конечно, они не так плохи, как умопомрачительный идиотизм фреймворков HTML / CSS, но это не совсем сюрприз, поскольку они, кажется, идут рука об руку с точки зрения того, кто их использует; тем более поток неубедительных отговорок, полуправды и откровенной лжи они повторяют. Это тот же танец, только другая мелодия.

Идите прямо к DOM и обойдите весь felgercarb.

- РЕДАКТИРОВАТЬ -
Я написал продолжение, основанное на многих более существенных ответах и ​​контрапунктах, которые вы оставили в комментариях. Вы не передумали, но заставили меня задуматься.