October 9

Задачи на собеседование

Теоретическая часть

Браузер:

  1. Какие процессы происходят в браузере, после получения HTML от сервера и до его парсинга ? (критические этапы рендера)
  2. В чем разница между Session Storage, Local Storage и cookie ?
  3. В чем отличие DOM от RenderTree ? Привести примеры, какие сущности могут быть в DOM и отсутствовать в RenderTree, и наоборот.
  4. Какие стадии распространения события по DOM дереву ты знаешь ?
  5. Можно ли обработать событие на стадии погружения ?
  6. Как остановить всплытие события ? (stopPropagation)
  7. Как остановить любое дальнейшее РАСПРОСТРАНЕНИЕ события ? (stopImmediatePropagation)

Сетевые технологии

  1. Какие методы HTTP запросов ты знаешь ?
  2. Что такое REST ?
  3. Можно ли сказать, что методы - это всего лишь семантика, а не жесткие ограничения ?
  4. Задача - реализовать чат с обновлением сообщений real-time. Можно ли это сделать с помощью обычного HTTP ? Какими способами это сделать удобнее ?
  5. Какие группы кодов ответов от сервера ты знаешь ? За что отвечают 300-ые коды ?
  6. Что такое DNS ?
  7. Что такое CDN ?

HTML / CSS

  1. Что такое семантика DOM-элементов ?
  2. Что такое data-атрибуты ?
  3. Можно ли использовать в CSS переменные ?
  4. Какие ты знаешь псевдоклассы ? Какие ты знаешь псевдоэлементы ? А кроме after/before ?
  5. Какие значения свойства positon ты знаешь ?
  6. В чем отличие display: none от visibility: hidden ?
  7. Что такое контекст наложения (stacking context) ? Что кроме z-index создает под собой контекст наложения ?
  8. Что такое вендорные префиксы (-webkit-, -moz-, -o-) и зачем они нужны ?

Javascript

Области видимости, hoisting, лексическое окружение

let value = 2;

function showValue() {
     console.log(`showValue ${value}`);
}

function wrapper() {
		 var value = 3;
     
		 console.log(`wrapper ${value}`);
     
     showValue();
}

wrapper(); - ?
var foo = 123;

if (true) {
    var foo = 456;
}

console.log(foo); - ?

Контекст функций

var side = 20;

const square = {
    side: 5,
    area() {
        return this.side * this.side;
    },
    perimeter: () => 4 * this.side
};

console.log(square.area()); - ?
console.log(square.perimeter()); - ?

Потеря контекста

var side = 20;

const square = {
    side: 5,
    area() {
        return this.side * this.side;
    },
    perimeter: () => 4 * this.side
};

const area = square.area;
console.log(area()); - ?
var side = 20;

const square = {
    side: 5,
    area() {
        return this.side * this.side;
    },
    perimeter: () => 4 * this.side
};

function foo(cb) {
	console.log(cb())
}

foo(square.area)

Присвоение контекста

var side = 20;

const square = {
    side: 5,
    area() {
        return this.side * this.side;
    },
    perimeter: () => 4 * this.side
};

const area = square.area.bind(square).bind({ side: 7 });
console.log(area()); - ?

Event Loop

Junior/Middle-level

setTimeout(() => console.log(2), 0);

console.log(1);

new Promise(res => {
    console.log(6);
    res();
    console.log(3);
}).then(() => console.log(4));

console.log(5);

Senior/TechLead-level

setTimeout(() => console.log(0), 3000);

console.log(1);

new Promise(async (resolve, reject) => {
  console.log(2);
  resolve(3);

  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        new Promise((resolve, reject) => {
            reject(4);
            console.log(5)
        })
        .catch(console.log)
        console.log(6)
    }, 0)

    resolve(7)
  })

  await promise.then(console.log)

  console.log(8)
})
.then((res) => console.log(res))
.catch((error) => console.log(error))

console.log(9);

Ответ: 1 2 9 7 3 8 5 6 4 0

Promise

Promise.resolve(1)
     .then(x => x + 1)
     .then(x => { throw x })
     .then(x => console.log(x))
     .catch(err => { console.log(err); return; })
     .finally(res => console.log(res))
     .then(x => Promise.resolve(1))
     .catch(err => console.log(err))
     .then(x => console.log(x));

Прототипы

// Реализовать customMap, который полностью повторяет функционал
// нативного Array.map

const arr = [1, 2, 3, 4, 5]

const multipleArr = arr.customMap((item) => item * 2)
console.log(multipleArr) // [2, 4, 6, 8, 10]
const obj = Object.create(null)

console.log(obj.hasOwnProperty('__proto__'))

Typescript

const a = 2;
const b = 3;

const logger = (c: typeof b) => {
	console.log(c);
}

logger(2);
// Типизировать функцию test любым способом
const test = () => {

}

test('test string'); // ✅ 
test(2, 3); // ✅ 

test('str', 3) // ❌
test(3, 'str') // ❌
test('str', 'str') // ❌
test(3) // ❌
type NonNegativeInteger =

const a: NonNegativeInteger = 42;  // OK
const b: NonNegativeInteger = 0;   // OK
const c: NonNegativeInteger = -10; // Error

React

// Что произойдет при клике по кнопке?
export default function Counter() {
  let count = 0;
 
  const changeCount = () => {
    count += 1;
  }
 
  return (
    <div>
      <h1>Counter</h1>
      <div>{count}</div>
      <button onClick={ changeCount }>Change count</button>
    </div>
  );
}
const CounterContext = createContext(null);

const B = ({counter}) => {
    const counterFromContext = useContext(CounterContext)

    return (
        <>
            <div>{counter}</div>
            <div>{counterFromContext}</div>
        </>
    )
}

// Сколько рендеров А и B будет при нажатии на кнопку?
const A = () => {
    const [counter, setCounter] = useState(0);

    return (
        <CounterContext.Provider value={counter}>
            <button onClick={() => setCounter((prev) => prev + 1)}>Click me</button>
            <B counter={counter} />
        </CounterContext.Provider>
    )
}
const CounterContext = createContext(null);

const B = ({counter}) => {
    const counterFromContext = useContext(CounterContext)

    return (
        <>
            <div>{counter}</div>
            <div>{counterFromContext}</div>
        </>
    )
}

const A = () => {
    const [counter1, setCounter1] = useState(0);
    const [counter2, setCounter2] = useState(0);

		// Поменяется ли количество рендереов в таком случае?
		const handleClick = () => {
				setCounter1((prev) => prev + 1)
				setCounter2((prev) => prev + 1)
		}

    return (
        <CounterContext.Provider value={counter2}>
            <button onClick={handleClick}>Click me</button>
            <B counter={counter1} />
        </CounterContext.Provider>
    )
}
export default function App(props) {
  // Реализовать хук useFirstRender
  const isFirstRender = useFirstRender();
 
  if(isFirstRender) return null;
 
  return props.children
}
export default function PreviousComponent() {
    const [number, setNumber] = useState(0);
    
    // Реализовать хук usePrevious
    const previousNumber = usePrevious(number);

    return (
        <div>
            <p>previousNumber: {previousNumber}</p>
            <p>currentNumber: {number}</p>
            <button onClick={() => setNumber(Math.floor(Math.random() * 100))}>
                Random number
            </button>
        </div>
    )
}
// Указать неточности и то что можно было бы исправить.
import React from "react";
 
const pleaseReviewMe = () => {
  const [count, setCount] = React.useState(1);
  const [items, setItems] = React.useState([{ id: 1 }]);
   
  React.useLayoutEffect(() => {
    setInterval(() => console.log(count), 1000);
  });
 
  const click = React.useCallback(() => {
    setCount(count + 1);
    setItems([...items, { id: count + 1 }]);
  } );
 
  return (
    <React.Fragment>
      <ul>
        {items.map((item) => (
          <li key={Math.random()}>{item.id}</li>
        ))}
      </ul>
      <button key='button' onClick={() => click()}>add one</button>
    </React.Fragment>
  );
};

export default PleaseReviewMe;
// Указать неточности и то что можно было бы исправить.
import React from 'react';

const pleaseReviewMe = () => {
  const [name, setName] = React.useState('');
  const [user, setUser] = React.useState({ name: '' });
  const [items, setItems] = React.useState([]);
  const [count, setCount] = React.useState(0);
  
  React.useLayoutEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users')
      .then((response) => response.json())
      .then((data) => setItems(data))
      .catch((error) => console.log(error));
  });
  
  React.useEffect(() => {
    setUser({ name });
  }, [name]);
  
  const click = () => {
    setCount(count + 1); 
    setTimeout(() => {
      console.log(`Вы кликнули ${count + 1} раз`);
    }, 300);
  };
  
  return (
    <div style={{ padding: '20px', color: 'blue' }}>
      <h2>Привет, {user.name}!</h2>
      <button onClick={click}>Кликни для счетчика</button>
      <input
        value={name}
        placeholder='Введи имя'
        onChange={(e) => setName(e.target.value)}
      />
      <p>Счетчик кликов: {count}</p>
      <p>Список всех пользователей с сервера:</p>
      <ul>
        {items.map((item) => (
          <li key={Math.random()}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default PleaseReviewMe;

Лайв-кодинг

Анаграммы (Junior/Middle-)

Задача - http://jsbin.com/fuvawuk/6/edit?js,output

Решение - https://jsbin.com/cujiqocopo/edit?js,output

Сортировка и группировка (Junior/Middle-)

Задача - http://jsbin.com/noracaq/5/edit?js,output

Решение - https://jsbin.com/zadazuduto/edit?js,output

Шпион (Middle/Middle+)

Задача - http://jsbin.com/kohaxip/4/edit?js,output

Решение - https://jsbin.com/xokijigaye/edit?js,output

Банкомат (Middle/Senior)

Задача - https://jsbin.com/kiwuxig/edit?js,output

Решение - https://jsbin.com/caraxexozi/edit?js,output

Цепочка промисов (Junior)

Задача - http://jsbin.com/kiyipop/3/edit?js,output

Решение - https://jsbin.com/dusibozone/edit?js,output

Множители чисел (Middle)

Задача - https://jsbin.com/makixeg/edit?js,console,output

Решение - https://jsbin.com/kotuzof/edit?js,console,output