История создания Javascript
Brendan Eich (создатель языка JavaScript) между делом пишет о том, как язык создавался, и почему он такой, какой есть.
JS был обязан «выглядеть как Java», только поменьше, быть эдаким младшим братом-тупицей для Java. Кроме того, он должен был быть написан за 10 дней, а иначе мы бы имели что-то похуже JS.
…
что-то вроде PHP, только еще хуже. Его босс Netcsape быстро «зарубил» (в июле 1995, если мне не изменяет память; я сдлелал JS в начале/середине мая), т.к. это был уже третий язык после Java и JS. Было и так трудно обосновать то, что у нас 2 новых языка программирования для web.
…
В то время мы должны были двигаться очень быстро, т.к. знали, что Microsoft идет за нами.
…
Считайте, что JavaScript (пожалуйста, только не «JScript») спас вас от VBScript.
…
10 дней на то, чтобы сделать лексер, парсер, компилятор в байткод (bytecode emitter), интерпретатор, встроенные классы и декомпилятор. Помощь была только с файлом jsdate.c — от Ken Smith из Netscape (который, по нашему излишне оптимистичному соглашению, склонировал java.util.Date — Y2K баги и т.д. Гослинг. ).
Простите, времени было мало для того, чтобы сделать правильную оптимизацию хвостовой рекурсии. 10 дней почти без сна, чтобы сделать JS с чистого листа, заставить его «выглядеть как Java» (я сделал, чтобы он выглядел как C), и тайком протащить туда его спасительные фишки: first class functions (замыкания сделал позже, но они были частью плана сразу) и прототипы (примерно как в языке Self).
I’ll do better in the next life.
Место и понимание ООП в программировании — JS: Введение в ООП
Что же такое ООП? Ответ, который наверняка встретится в сети первым, будет звучать так: наследование, полиморфизм и инкапсуляция. Если копнуть глубже, то кроме этих понятий всплывут «передача сообщений», «класс», «абстрактный класс», «прототипы», «интерфейсы», «диспетчеризация», «миксины», «протокол», «мультиметоды» (и еще сотня других страшных слов!). Причем в каждом языке есть свой набор таких сущностей, который встречается только в этом языке или в языках похожих на него. И каждый будет утверждать, что ООП не ООП без этих понятий.
Дальнейший поиск покажет, что в сети очень много статей на тему «я не понял ООП» (в таких статьях всегда обвиняют автора в том, что он не осилил) или вопросов «как понять ООП?». Под этими статьями, обычно, сотни комментариев, где обязательно разворачиваются жаркие споры о сути ООП. Среди этих споров обязательно появятся люди, которые скажут, что JS не ООП язык, ООП без классов не бывает, а кто-то скажет, что единственные ООП-языки это Smalltalk и Lisp. Один из самых классных примеров — это статья на Хабре Я не знаю ООП . Под этой статьей 870 комментариев.
А вишенка на торте — непрерывный поток статей в стиле «ООП для чайников», которые на примере животных (или кораблей, машин — чего угодно из реального мира) пытаются объяснить ООП, создавая у программистов ложную иллюзию того, что они поняли о чем идет речь. А потом эти программисты открывают код, а там адаптеры к базе данных и никакого реального мира.
Кто виноват и что делать?
У ООП долгая и непростая история. Этот термин придумал Алан Кей в конце семидесятых, когда работал над языком Smalltalk.
Вот, что он сказал по этому поводу:
Для меня ООП — это сообщения, локальное удержание и защита, скрытие состояния и позднее связывание всего. Это можно сделать в Smalltalk и в LISP.
Я считал объекты чем-то вроде биологических клеток или отдельных компьютеров в сети, которые могут общаться только через сообщения.
Забавно, но в каком-то смысле он предвидел интернет
Затем появился язык C++, по мотивам которого была создана книга «Объектно-Ориентированный Анализ». В этой книге Гради Буч, создатель UML , описал те самые «полиморфизм, наследование и инкапсуляция». C++ стал мейнстримом и все последующие «ООП-языки» стали его копировать.
Когда Алана спросили про ООП в C++, он сказал следующее:
Когда я придумал ООП, я не имел в виду C++
С тех пор прошло много времени. Современное (не значит, что оно лучшее, это всего лишь текущее состояние дел) понимание ООП невероятно сильно отличается от того, что имел в виду Алан Кей. Это не значит, что его идеи умерли. Они живы, но иногда в других формах и на другом уровне. Хотя некоторые разработчики продолжают настаивать на том, что настоящее ООП — это ООП Алана, всё остальное — не настоящее. Мы не будем подробно останавливаться на этом. Главное запомнить – когда программисты начинают говорить про ООП, очень важно понимать, про какое ООП они говорят, иначе будут возникать споры и даже конфликты. ООП относится к «религиозным» темам.
Современное ООП — это не строгая обоснованная теория, в отличие от функционального или автоматного программирования. Это большой набор разнообразных подходов к организации кода и сущностей (классы, объекты и т.п.), которые иногда настолько сильно различаются в разных языках, что это приводит к совершенно удивительным ситуациям. Программисты на PHP приходят в ужас от того, что называется ООП в Ruby. Создатели Ruby, при этом, говорят, что Ruby — «настоящий» ООП язык, потому что в Ruby «всё есть объект». А Java-разработчики никогда не поверят, что в JavaScript ООП вообще присутствует.
В такой ситуации очень важно отсечь всё лишнее и найти те вещи, без которых программу назвать объектно-ориентированной не получится. Как говорят математики, найти базис (минимальный набор элементов, из которых можно вывести всё остальное).
ООП приписывается множество вещей, которые существовали и прекрасно существуют без ООП прямо сегодня во многих языках. Поэтому когда вы слышите про какие-то преимущества ООП, не воспринимайте эти слова за чистую монету. Эти преимущества, как правило, являются преимуществами только потому, что именно в этом языке по-другому сделать сложнее либо невозможно. Вы всегда можете найти язык, в котором эти же концепции решены очень элегантно и эффективно, но без классов и объектов.
Почему же тогда надо учить ООП? Именно этот подход стал доминировать в популярных языках. В JS, к счастью, достаточно сильная мультипарадигменность (то есть можно писать в разных стилях). То есть программы на JS могут легко комбинировать внутри себя разные стили, например, функциональный и ООП. В тех местах, где это оправдано, мы будем реализовывать код, используя разные стили. Тогда вам будет проще отделять суть задачи от способа ее решения. Вы научитесь выбирать нужное решение по ситуации, а не на основе заученного синтаксиса.
Обучение
При изучении ООП нужно иметь в виду одну важную мысль. Ни один курс не способен разложить в голове по полочкам ООП от и до. Для этого нужны годы опыта, копание в плохих и хороших архитектурах, переписывание кода и, самое главное, постоянный анализ сделанного, только в таком случае будет происходить улучшение.
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
Что такое каррирование в JavaScript
Когда мы объявляем функцию, то можем передать ей аргументы — данные, которые функция будет обрабатывать. Функции без разницы, сколько аргументов получать на входе, — она справится со всеми. Но иногда программистам неудобно перечислять много переменных при вызове функции. А иногда функция становится настолько сложной, что можно запутаться, какой аргумент за что отвечает и что туда нужно передать.
Чтобы в таких ситуациях разработчикам было проще, придумали каррирование — с ним можно уменьшить количество аргументов без потери работоспособности функции.
Что такое функция
Функция в программировании — это код внутри основной программы, у которого есть своё внутреннее имя. Если использовать имя функции как команду, то программа выполнит этот мини-код, а потом продолжит работу дальше. Это делает код проще и чище, избавляет от повторов, ускоряет разработку, тестирование и совместную работу.
Например, вы пишете игру. Каждый раз, когда игрок попадает в цель, убивает врага, делает комбо, заканчивает уровень или падает в лаву, вам нужно добавить или убавить ему очков. Это делается двумя действиями: к старым очкам добавляются новые, на экран выводится новая сумма очков. Допустим, эти действия занимают 8 строк кода.
Представим, что в игре есть 100 ситуаций, когда нужно добавить или убавить очки — для каждого типа врага, преграды, уровня и т. д. Чтобы в каждой из ста ситуаций не писать одни и те же восемь строк кода, вы упаковываете эти восемь строк в функцию. И теперь в ста местах вы пишете одну строку: например, changeScore(10) — число очков повысится на 10.Если теперь изменить, что происходит в функции changeScore() , то изменения отразятся как бы во всех ста местах, где эта функция вызывается.
Что такое каррирование
Каррирование функций — это преобразование функции с любым количеством аргументов в функцию только с одним аргументом. Это сработает, только если количество аргументов в функции ограниченное, а не бесконечное (а такое тоже может быть, например с необязательными аргументами).
На английском такое преобразование называется currying, а на русском это звучит как карринг, или каррирование. Этот приём изобрёл математик Хаскелл Карри — тот самый, в честь которого назвали язык программирования Haskell.
Проще говоря, каррирование — это когда мы берём функцию, у которой много аргументов, и превращаем всё это в функцию, у которой только один аргумент.
Каррирование в JavaScript
Возьмём простую функцию, которая перемножает три аргумента:
function multiply(a, b, c) return a * b * c;
>
Если мы вызовем её как multiply(2, 4, 8), то получим число 64: 2 × 4 × 8 = 64
Теперь выполним каррирование. Чтобы получить функцию только с одним аргументом, сделаем так:
- Сделаем функцию с одним аргументом (a).
- Внутри этой функции сделаем вложенную функцию с аргументами (b,c).
- Во вложенной функции перемножим a на b × c.
В классическом каррировании мы получим три функции, каждая из которых будет с одним аргументом:
- Сделаем функцию с одним аргументом (a).
- Внутри этой функции сделаем вторую вложенную функцию с аргументом (b).
- Внутри этой функции сделаем третью вложенную функцию с аргументом (с).
- Во третьей вложенной функции перемножим a на b и на c и вернём это как результат.
Запишем это на JavaScript, используя стрелочные функции:
function multiply(a) < return (b) => < return (c) => < return a * b * c >> > multiply(2)(4)(8);

Суть в том, что мы превратили multiply(1,2,3) в multiply(1)(2)(3) и получили вместо одной функции серию последовательных функций. Мы не умножаем сразу 2 на 4 на 8. Вместо этого мы сначала берём 2, умножаем на 4 и потом результат умножаем на 8.
Сейчас может показаться, что у нас как было три аргумента, так и осталось, только стало сложнее. Но это потому, что мы сделали самый наглядный учебный пример, а на практике всё интереснее.
Практика
Допустим, мы хотим, чтобы программа приветствовала пользователя по имени. Без каррирования код можно написать так:
// объявляем функцию через переменную // в функции — два аргумента var greet = function(greeting, name) < // выводим приветствие и имя console.log(greeting + ", " + name); >; // запускаем функцию, указав приветствие и имя greet("Привет", "Лена");

С помощью каррирования код можно переписать так, что базовая функция будет требовать только приветствие, а имя возьмёт из вложенной функции:
// объявляем основную функцию, которая сначала отвечает за формулировку приветствия var greetCurried = function(greeting) < // результат — новая функция, которая формирует приветствие, добавляя к нему имя // имя — это аргумент для этой вложенной функции return function(name) < // выводим полный текст приветствия console.log(greeting + ", " + name); >; >;
Теперь мы можем создать новую функцию для любого типа приветствия и передать ей имя человека:
// создаём новую переменную-функцию, в которой сразу прописываем стандартное приветствие
var greetHello = greetCurried(«Здравствуй»);
// запускаем каррированную функцию всего с одним аргументом, хотя изначально их было два
greetHello(«Лена»);
При этом у нас остаётся полный контроль над каррированной функцией — мы можем вызывать её напрямую, передав каждый из параметров в скобках:

Зачем и где применяют каррирование
Каррирование позволяет разбить сложные функции со множеством аргументов на более простые функции. Код становится более компактным, его проще переиспользовать.
Представим, что мы рассчитываем скидки для покупателей нашего магазина по такой формуле, где price — цена товара, discount — объём скидки:
function disc(price, discount) return price * discount
>
В этой функции два аргумента. Если процент скидки для всех покупателей одинаковый, можно каррировать функцию, оставив в ней всего один аргумент:
function disc(discount) return (price) => return price * discount;
>
>
Если мы предлагаем скидку 5%, система будет автоматически умножать стоимость товара на 0,05.
Каррирование позволяет объединять несколько простых функций в одну. Например, мы хотим, чтобы по умолчанию у нас шла скидка 5% почти для всех покупателей. Но особо лояльным клиентам мы готовы дать повышенную скидку, которую будем рассчитывать по индивидуальной формуле. Чтобы реализовать эту идею, мы будем колдовать с функцией disc(discount) .
Каррирование упрощает тестирование кода, который состоит из отдельных независимых друг от друга блоков. Например, мы рассчитываем объём серии цилиндрических объектов. l — длина, w — ширина, h — высота:
function volume(l, w, h) return l * w * h;
>
Оказывается, что высота у всех цилиндров одинаковая, 70 см. Это позволяет нам упростить функцию volume с помощью каррирования:
function volume(h) < return (w) => < return (l) => < return l * w * h >> > // сразу упрощаем будущие вызовы, где можно указывать теперь два аргумента вместо трёх var newVolume = volume(70);
JS c помощью regexp найти в json ключ и изменить его значение
Столкнулся с задачей — нужно регуляркой найти в json пару «name» : «oldName» и заменить «oldName» на «newName» Придумал пока только так: data.replace( /»name»:\s».*»/g, ‘»name»: «newName»‘ ); Но по условию нужно изменить только «oldName», все остальное только помогает найти, что менять Вместо oldName может быть любой текст Кто может подкинуть идею?
- javascript
- регулярные-выражения
Отслеживать
задан 18 фев 2022 в 15:35
Измените .* на [^»]* . Или .*? .
18 фев 2022 в 15:44
Спасибо, я изменил .* на .*?. Но все равно таким образом я заменяю всю пару ключ-значение «имя»: «oldName», а мне нужно заменить только значение «oldName»
18 фев 2022 в 19:26
Да не вопрос, используйте захватывающие подмаски и обратные ссылки, data.replace( /(«name»\s*:\s*»)[^»]*/g, ‘$1newName’);
