Среди разработчиков самые нетривиальные и ответственные задачи, пожалуй, решают фронтендеры. Как сделать конечный продукт понятным и удобным? Как обеспечить кроссплатформенность? Что сделать, чтобы сайт работал без тормозов? Если вас не пугают эти задачи, то мы совместно с Tinkoff.ru предлагаем вам решить несколько несложных задач для будущих разработчиков компании. После завершения теста вы можете оставить свою электронную почту и попасть на второй этап собеседования в девяти городах: Москве, Санкт-Петербурге, Нижнем Новгороде, Екатеринбурге, Ижевске, Рязани, Ростове-на-Дону, Новосибирске и Иннополисе.

Короткая программа

Фронтендер добавила в чат поддержки виджет emoji и отдала в тестирование. «У меня одни квадраты», — сообщил тестировщик с Linux. «Может, цветными их сделаем?» — спросил технолог c Windows 7.
Помогите доделать виджет — поддержите цветные emoji для всех популярных браузеров, сохраняя нативные иконки «под капотом». Наверняка придется прибегнуть к помощи сторонних библиотек, но все они работают медленнее нативных смайлов. Придется исхитриться, чтобы не испортить клиентам впечатление длительными прокрутками или скачиванием всего бандла картинок при открытии виджета с emoji.

HTML
<div class="emoji-picker">

</div>
<div class="message">

</div>
CSS
body {
  margin: 20px;
}
.emoji-picker {
  position: relative;
  width: 200px;
  height: 200px;
  overflow-y: scroll;
  background: #fff;
  box-shadow: 0 0 10px rgba(0, 0, 0, .5);
  border-radius: 5px;
  padding: 10px;
}

.emoji-picker section + section {
  margin-top: 15px;
}

.emoji-picker section h2 {
  margin: 0 0 5px;
  padding: 0 5px;
  font: 16px Arial
}

.emoji-picker ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
}

.emoji-picker ul li {
  text-align: center;
  display: inline-block;
  cursor: pointer;
  padding: 3px 0 0 5px;
  line-height: 1.4;
  border-radius: 3px;
}

.emoji-picker ul li:hover {
  background: #FFC206;
}

.message {
  margin: 10px 0;
  padding: 5px 10px;
  background: #eee;
  min-height: 30px;
  border-radius: 5px;
}
JS
const picker = document.querySelector('.emoji-picker');
const message = document.querySelector('.message');

const EMOJI_DATA = [
  {
    title: 'Люди',
    icons: ['😃', '😁', '😅', '😇', '😍', '🤡', '🤠', '😎', '😡', '😨', '😭']
  },
  {
    title: 'Котики',
    icons: ['😺', '😸', '😹', '😻', '😼', '😽', '🙀', '😿', '😾']
  },
  {
    title: 'Жесты',
    icons: ['👍', '👎', '👊', '✊', '✌️', '🤘']
  }
]

function addIcon(icon) {
  message.innerHTML += icon;
}

function renderEmojiList(icons) {
  return icons.map(icon =>
    `<li onclick="addIcon('${icon}')">${icon}</li>`
  ).join('')
}

function renderIconsGroup(group) {
  return `
    <section>
      <h2>${group.title}</h2>
      <ul>
        ${renderEmojiList(group.icons)}
      </ul>
    </section>
`
}

function renderIcons(emojiData) {
  return emojiData.map(group => renderIconsGroup(group)).join('');
}

picker.innerHTML = renderIcons(EMOJI_DATA);
Произвольная программа

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

const width = 34;
const height = 34;
const ctx = document.createElement('canvas').getContext('2d');
const img = new Image();

Object.assign(ctx.canvas, {width, height});

img.src = 'data:image/gif;base64,R0lGODlhIgAiAIIAMTIwMrSeTPzfMNTOzGdjYPz58VRONLCqqCwAAAAAIgAiAAID/ii63P4wykldKTWvW87V0zUABGB4GAh1xzAcRKquhcvN230ZQI8Ktwpn2InVAMSgJQlA1Qwi5wFJZESbHcNJRD1Aj94agTD4AAfa8ujZwV5KLw8BxfMoiKMy7O2cF8FVdy8EBmUFAIaHB15OiDsnZVYkiXtDi05sIjyRQIeJhyJjojCLO5+FMkdfoGIBrq9bBX6yWFYXVJ5ZDmO3HGRmG2tcLgQCrgQBxi1usj93fG+TMMZaxQFyPWqOH21GR6EKAQbhRrNtdp0GYyh+A8XU4Si46o457iilaOTxmfdKnQW+7HHn4FoWaDJsbXF36104R/moRNjhgYo7ZAFK0FlmLmhiNGbuUHGZBIyGiE94agzJQGROixqMAoG4AKOHzZc4bCUpmfNOJyA9gwoFkQAAOw==';

function consoleLog(...messages) {
  let parts = [''];
  for (let item of messages) {
    if (Array.isArray(item)) {
      const [message, color] = item;
      parts[0] += `%c${message}`;
    }
  }
  for (let item of messages) {
    if (Array.isArray(item)) {
      const [message, color] = item;
      parts.push(`font: 16px/10px monospace; background: ${color}; color: ${color}`);
    } else {
      parts.push(item);
    }
  }
  console.log.apply(console, parts);
}

img.onload = () => {
  ctx.drawImage(img, 0, 0);

  const {data} = ctx.getImageData(0, 0, width, height);

  console.clear();
  for (let y = 0; y < height; y++) {
    let attributes = [];
    for (let x = 0; x < width; x++) {
      let i = ((y * width) + x) * 4;
      const [r, g, b, a] = data.slice(i , i + 4); 
      attributes.push([`${i}`.padStart(2).substr(-2), `rgba(${r}, ${g}, ${b}, ${a})`]);
    }

    consoleLog(...attributes);
  }
};
Классика

Два числа представлены в виде связных списков, где каждый узел содержит одну цифру. Цифры хранятся в списке в обратном порядке. Необходимо перемножить такие списки.

Пример:
   Вход: (7 → 1 → 6 → 2)×(5 → 9 → 2), то есть 2617×295
   Выход: (5 → 1 → 0 → 2 → 7 → 7), то есть 772015

Реализуйте функцию multiplyLists(headNode1, headNode2), которая в качестве аргументов принимает головы двух списков и возвращает голову третьего списка, который является произведением первых двух. Чтобы реализовать эту функцию, необходимо реализовать еще несколько вспомогательных функций: сложение, умножение на цифру, а также сдвиг по разрядам. Конвертировать список в число и обратно не разрешается. Оперировать можно только узлами.

class Node {
    constructor(value, next = null) {
        this.value = value;
        this.next = next;
    }
}

function multiplyListByNumber(headNode, num, carry = 0) {
    …
}

function shiftListByZeros(headNode, digitsСounter) {
    …
}

function sumLists(headNode1, headNode2, carry = 0) {
    …
}

function multiplyLists(headNode1, headNode2) {
    …
}

const headNodeOfList1 = new Node(7, new Node(1, new Node(6, new Node(2))));
const headNodeOfList2 = new Node(5, new Node(9, new Node(2)));

const multipliedHeadNode = multiplyLists(headNodeOfList1, headNodeOfList2);
// Node {value: 5, next: Node {value: 1, next: Node {value: 0, next: Node {value: 2, next: Node {value: 7, next: Node {value: 7, next: null}}}}}
Предоставляя адрес электронной почты, вы принимаете условия соглашения о персональных данных.

Нашли опечатку? Выделите фрагмент и нажмите Ctrl+Enter.