• Как объединить массивы объектов так, чтобы в результирующем массиве значения определённого свойства были уникальны?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Создаём новый массив:

    const concat = (key, ...arrs) =>
      Object.values([]
        .concat(...arrs)
        .reduce((acc, n) => (acc[n[key]] = acc[n[key]] || n, acc), {})
      );
    
    
    const newFirst = concat('hour', first, hours);

    Дополняем существующий:

    function add(key, target, ...sources) {
      const unique = new Set(target.map(n => n[key]));
    
      for (const arr of sources) {
        for (const n of arr) {
          const k = n[key];
          if (!unique.has(k)) {
            unique.add(k);
            target.push(n);
          }
        }
      }
    
      return target;
    }
    
    
    add('hour', first, hours).sort((a, b) => a.hour - b.hour); // да, придётся делать сортировку вручную
    Ответ написан
    3 комментария
  • Как изменить стили SVG при использовании спрайта?

    werty1001
    @werty1001
    undefined
    При использовании use содержимое будет в Shadow DOM, он изолирован и изменить стили определенного узла из вне нельзя.

    - Можно изменять цвет, толщину границы, размеры но для всей иконки в целом.
    - С помощью currentColor можно задать сразу 2 цвета.
    - Если браузер умеет в CSS переменные, то можно красить иконки как хочешь.
    - В будущем возможно будет псевдо-селектор ::shadow, который позволит влезать в Shadow DOM, но это не точно.
    Ответ написан
    1 комментарий
  • Как создать массив из объекта?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const arr = Object.entries(obj).map(([ k, v ]) => ({ id: +k, name: v.nameEn }));
    Ответ написан
    Комментировать
  • Оцените качество кода?

    rockon404
    @rockon404
    Frontend Developer
    1. А теперь главный вопрос. Зачем было в модуле ES6 реализовывать module pattern? В этом нет абсолютно никакого смысла. Практика практикой, но все же.

    2. В наличии переменной posts так же нет никакого практического смысла.
    const { data } = await HTTP.get('posts');
    3. Функцию:
    async function _getPostById(id) {
        const post = await HTTP.get(`posts/${id}`)
        return post
      }


    Можно смело заменить на:
    const  _getPostById = id => HTTP.get(`posts/${id}`);

    То же можно сделать и с функцией _getPosts.
    4. Где-то let, где-то var, где-то const. Никакой логики в предпочтении одного ключевого слова другому при этом нет. Почитайте современные гайдлайны airbnb, например.
    5. Точки с запятой где-то есть где-то нет. Читать такой код неприятно.
    Ответ написан
    Комментировать
  • Как из класса убрать модификатор через js?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.querySelectorAll('[class*="toggle-"]').forEach(n => {
      n.className = n.className.replace(/(^|\s)toggle-/g, '$1');
    });
    Ответ написан
    Комментировать
  • Как обработать такой массив в аналогичный с уникальными значениями по свойству?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Object.values(arr.reduce((acc, n) => {
      const g = acc[n.family] = acc[n.family] || { ...n };
      g.variants = [...new Set([...g.variants, ...n.variants])];
      g.subsets = [...new Set([...g.subsets, ...n.subsets])];
      return acc;
    }, {}))
    Ответ написан
    6 комментариев
  • Какие есть JS библиотеки для оформления кода?

    Stalker_RED
    @Stalker_RED
    Похоже вы хотите "подсветку синтаксиса" но гуглите почему-то оформление кода, которое code style.
    Ответ написан
    1 комментарий
  • Как из двух массивов сделать объект с новыми свойствами?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const t = {
      1: 'region',
      3: 'area',
      7: 'street',
    };
    
    const newItems = items.map(n => ({
      id: n.id,
      name: n.name,
      ...n.parents_names.reduce((acc, name, i) => (
        acc[t[n.parents_levels[i]]] = name,
        acc
      ), {}),
    }));
    Ответ написан
    1 комментарий
  • Как правильно писать на ООП?

    TLDR: Все зависит от ситуации. Набивайте свои шишки и наберетесь опыта.

    Самый главный вопрос - зачем вы вообще хотите использовать ООП, насколько сложный и "правильный", какие цели хотите достичь.

    Когда разрабатываете библиотеку, то есть несколько важных целей (независимо от парадигмы):
    1. Апи должнен быть простым, понятным и самодокументируемым
    2. Вы должны иметь возможность развивать библиотеку и не нарушать при этом уже используемый пользователями API

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

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

    Не слушайте евангелистов ФП - сейчас в JS функциональностью модно прикрывать говнокод.

    Так же не слушайте тех, которые на каждом углу кричат "Composition over inheritance", "Banana monkey problem" другие страшные термины. В своем религиозном угаре они забывают, что все эти принципы рекомендации для определенных ситуаций. Да, иногда (в большинстве случаев на самом деле) композиция значительно лучше наследования, очень часто стыкаешься с ситуацией, что наследование применено не в тему и из-за этого усложнено развитие. Но иногда наследование - правильный путь и пока сами не набъете шишек - будет крайне сложно понять разницу. Помогает принцип is-a/has-a. И я видел код отличных программистов, где наследование было применено так, что значительно разгрузило API и упростило код. Не зацикливайтесь из-за религиозных фанатиков.

    Множество паттернов ООП придумано, чтобы изолировать функциональность и облегчить её тестирование, но каждый паттерн - лишь рекомендация.

    Получился класс, в котором есть эти 4 метода. Все эти методы я вызываю в конструкторе. То есть получается, я процедурный стиль просто запихнул в класс.
    Да, вы правы, но это не обязательно плохо, идеальный код никто и никогда не пишет. Но посмотрите какая проблема - у вас и парсятся входные данные и делается запрос и делается обработатка. Можно ли изменить парсинг входных данных, оставив другие шаги? Можно ли не отправлять запрос? Как вы будете тестировать эту функцию, если она обязательно выполняет запрос и нету никакого способа не дать ей отправить этот запрос?

    С другой стороны, будут ли довольны пользователи вашей библиотеки, если им придется инджектить все зависимости? Даже если вы сделаете вызов по-умолчанию, то чтобы изменить одну зависимость - придется изменять все. Я приведу пример, где использование наследования даст необходимую вам гибкость и API для пользователя не разбухнет, зато он сможет изменить каждый шаг. Вот:

    interface IPipeline {
    	ResultView Render (RawData rawData);
    }
    
    class Pipeline : IPipeline {
    	protected virtual ParsedRawData ParseRawData(RawData rawData) {
    		return new DataParser(rawData).GetParsedData();
    	}
    	
    	protected virtual ActualData GetActualData (ParsedRawData rawData) {
    		return new HttpRequest(rawData.src);
    	}
    	
    	protected virtual ResultState GetResultState (RawData rawData, ActualData actualData) {
    		return new StateCounter().Count(rawData, actualData);
    	}
    	
    	public virtual ResultView Render (RawData rawData) {
    		var parsed = ParseRawData(rawData);
    		
    		if (parsed.IsValid) {
    			var actual = GetActualData(rawData);
    			var state = GetResultState(rawData, response);
    			return new Renderer().Render(state);
    		} else {
    			throw new Exception("Raw data is invalid");
    		}
    	}
    }


    Для пользователя это выглядит довольно симпатично:
    new Pipeline().Render(rawData);

    Если же ему необходимо брать из другого источника данные - он легко это исправит:
    class MyPipeline : Pipeline {
    	protected virtual ActualData GetActualData (ParsedRawData rawData) {
    		return new LocalStorageRequest(rawData.src);
    	}
    }
    
    new MyPipeline().Render(rawData);


    Конечно, это же можно сделать при помощи композиции. Ну давайте поиграем на основе паттерна Билдер:

    interface IPipeline {
    	ResultView Render (RawData rawData);
    }
    
    class Pipeline : IPipeline {
    	private IRawDataParser rawDataParser;
    	private IActualDataReciever actualDataReciever
    	private IResultStateCounter resultStateCounter;
    	private IRenderer renderer;
    	
    	public GetRawDataParser () {
    		return rawDataParser ?? new RawDataParser();
    	}
    	public GetActualDataReciever () {
    		return rawDataParser ?? new ActualDataReciever();
    	}
    	public Pipeline GetActualDataReciever (actualDataReciever) {
    		actualDataReciever = actualDataReciever;
    		return this;
    	}
    	
    	// ...
    	private GetRenderer () {
    		return renderer ?? new Renderer();
    	}
    	
    	
    	public virtual ResultView Render (RawData rawData) {
    		
    		var parsed = GetRawDataParser().Parse(rawData);
    		
    		if (parsed.IsValid) {
    			var actual = GetActualDataReciever().Get(rawData);
    			// ...
    			return GetRenderer().Render(state);
    		} else {
    			throw new Exception("Raw data is invalid");
    		}
    	}
    }


    Использование по-умолчанию всё то же:
    new Pipeline().Render(rawData);

    А изменить пользователь их может так:
    new Pipeline()
    	.SetActualDataReciever(new MyDataReciever())
    	.Render(rawData);


    Тут впору уже и о DI Container'ах почитать.

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

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

    @itsjustmypage
    Outline это контур элемента с внешней его стороны, то есть сразу за border. В отличие от border он никак не влияет на элементы, их ширину и расположение. Ключевое слово inset в свойстве outline: inset 100px green; устанавливает этот контур в виде псевдотрехмерной рамки за счёт осветления правой и нижней границ и затемнения левой и верхней относительно указанного цвета. Ширина 100px, цвет зелёный.

    Баг создаёт свойство outline-offset: -125px;, которое задаёт смещение контура. При положительном значении контур будет расширяться во все стороны. А при отрицательном будет сжиматься внутрь элемента.

    Спецификация CSS Basic User Interface Module Level 3 в статусе рекомендации говорит о том, что контур элемента со свойством outline-offset при отрицательном значении не должен становиться меньше, чем двукратная вычисляемая ширина контура. То есть если в примере у нас размеры элемента 100x100 пикселей и контур задан у нас шириной 100px, то при outline-offset: -125px; он должен сжаться внутрь элемента на 125px со всех сторон, а спецификация визуально ограничивает сжатие до outline-offset: -50px; (по 50px внутрь с каждой стороны элемента). То есть контур должен просто сойтись вместе со всех сторон, образуя квадрат в нашем случае и насколько больше не ставь отрицательное значение, больше он сжиматься не должен. Но реализация в браузерах не учитывает это поведение и выдаёт непонятные фигуры, если отрицательное значение слишком большое.

    https://www.w3.org/TR/css-ui-3/#outline-offset
    5b447ea6c9061121780680.jpeg

    Поведение при отрицательном outline-offset должно быть как на гифке. Если дальше уменьшать значение, ничего меняться не должно. AMQ4hnM.gif
    Ответ написан
    1 комментарий
  • Какие уровни кода?

    операций к процессору

    К какому - реальному или виртуальному? Байт-кодом называют опкоды виртуальной машины/процессора. Например, jvm, clr.
    0) Микрокод.
    1) Машинный код (оно же "опкоды" или байт-код, в случае виртуального процессора).
    2) Язык ассемблера (который транслируется в машинный код)
    3) Высокоуровневые языки, которые также транслируются: или в язык ассемблера, или сразу в машинный код.
    Ответ написан
    1 комментарий
  • Для чего нужно ООП?

    Stalker_RED
    @Stalker_RED
    Для управления сложностью.
    https://habrahabr.ru/post/169487/

    Все что сделано при помощи ООП можно написать и в процедурном стиле, например, но чем сложнее проект тем сложнее будет во всей этой каше разобраться. Весь смысл ООП - разбить большущую сложную систему на кучу отдельных ПРОСТЫХ объектов, методов, сущностей.
    А еще с ООП неразлучна абстракция. Чтобы можно было одну часть программы выбросить и подменить на другую.

    Сегодня у нас выводится на веб-страничку, по которой кликают мышкой, а завтра не мышкой - а тач пальцами. А послезавтра вообще в VR шлем, и управление голосом. И если система правильно спроектирована - ее не придется переделывать ПОЛНОСТЬЮ, а только ту часть, которая ответственна за ввод/вывод.
    Ответ написан
    Комментировать
  • Как правильно писать на ООП?

    Xuxicheta
    @Xuxicheta
    инженер
    У вас линейная обработка данных, это одна процедура, а вы сделали класс ради класса.

    Вообще в js я начал стараться предпочитать функциональный стиль там, где это возможно.
    Даже методы пишу максимально похожими на чистые функции. Так проще переиспользовать их в других местах и, вообще, понятнее что происходит.
    А то уже замучался разбираться с этим хардкорным ООП, которое встречается сплошь и рядом.

    Качественный класс написать сложно, плюс наследование в js не особо рекомендуется. А для композиции лучше подходят простые функции.
    Ответ написан
  • Как правильно писать на ООП?

    Adamos
    @Adamos
    ООП - это компьютерная мечта о дамской сумочке. Которая большая внутри и крошечная снаружи.
    Главное в хорошем классе - это интерфейс, позволяющий вообще не думать о том, что находится внутри класса.
    Представьте себе черный ящик, решающий вашу задачу. Сформулируйте, каких внешних данных ему должно быть достаточно и какими внешними же признаками и логикой должен обладать этот ящик. Старательно абстрагируясь от того, что там будет происходить внутри (процедурное программирование приучает думать об этом, придется напрячься).

    Простейший пример - jQuery.cookies. Кукисы в браузере хранятся неудобно для редактирования, но это проблемы внутри черного ящика, снаружи их быть не должно. Снаружи вам надо поставить куку и прочитать куку. С коротким списком возможных свойств. Вот это класс и реализует, вполне успешно. Буквально одним методом.
    Мог бы этот метод быть простой процедурой? Да, конечно. Но как раз это - неважно.
    Ответ написан
    2 комментария
  • Как подключить к img уже загруженное изображение?

    Vlad_IT
    @Vlad_IT Куратор тега JavaScript
    Front-end разработчик
    Не очень понятен момент. Вы загружаете картинку от пользователя на сервер, и от туда ее показываете? В таком случае, технически это разные картинки (с сервера и у пользователя). Вы можете попробовать получить картинку из input file вот так https://codepen.io/mobifreaks/pen/LIbca
    Ответ написан
    8 комментариев
  • Как сформировать версию продукта?

    rockon404
    @rockon404
    Frontend Developer
    В npm такое соглашение:
    1.0.0 - начальная стабильная версия
    1.0.1 - patch release, небольшие исправления, функциональность не меняется
    1.1.0 - minor release, добавление новой функциональности, сохраняется поддержка старой функциональности
    2.0.0 - major release, новая функциональность, не сохранена поддержка прерыдущих версий

    [link]
    Ответ написан
    1 комментарий
  • Как правильно организовать структуру класса?

    Если что-то попроще, но при этом более-менее ООПшное, то можно как-то так:

    class Plugin {
    
    	constructor (rawUrl, rawName) {
    		this.url = new UrlParser(rawUrl);
    		this.name = new NameParser(rawName);
    	}
    
    	doSomething () {
    		// code
    	}
    }
    
    function userCode() {
        new Plugin("example.com", "FooBar").doSomething()
    }


    Если хотите побольше DI и всего такого, но при этом не потерять лёгкость использования, то можно так:

    class Plugin {
    
    	constructor (urlParser, nameParser) {
    		this.url = urlParser;
    		this.name = nameParser;
    	}
    	
    	doSomething () {
    		// code
    	}
    
    }
    
    Plugin.init = function (url, name) {
    	return new Plugin(
    		new UrlParser(url),
    		new NameParser(name)
    	);
    }
    
    function userCode() {
    	Plugin.init("example.com", "FooBar").doSomething()
    }


    UrlParser и NameParser - это классы, которые парсят всё необходимое, а потом внутри имеют свойства для обращения к ним.

    class UrlParser {
    
    	constructor (urlString) {
    		var result = this.matchUrlStrign(urlString)
    		
    		this.anchor = result[0];
    		this.path   = result[1];
    		// etc
    	}
    }


    Соответственно, в плагине используете как-то так:
    this.url.anchor
    Ответ написан
    3 комментария
  • Как сверстать такие круги?

    Алгоритм распределения можно взять из:

    Canvas
    1) https://codepen.io/valhead/pen/oLrqaN
    2) jsfiddle.net/SalixAlba/7mAAS

    Svg bl.ocks.org/bycoffe/3404776
    Ответ написан
    Комментировать