HimeraSearchDB
Carding_EbayThief
triada
CrackerTuch
JustinSun

НОВОСТИ [Перевод] Вопросы, которые мне задавали на фронтенд-собеседованиях

NewsBot
Оффлайн

NewsBot

.
.
Регистрация
21.07.20
Сообщения
40.408
Реакции
1
Репутация
0
Всем привет. В сентябре OTUS вновь запускает целую линейку курсов по JavaScript. Прямо сейчас вы можете посмотреть запись открытого урока по курсу , а также зарегистрироваться на дни открытых дверей по курсам и . Ну а мы традиционно делимся с вами переводом полезного материала.

fa12ff444fd5a8440945e3ac91f3daf4.png








Вопросы, которые задавали на фронтенд-собеседованиях


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


Вопросы я разделил на четыре части.


  • JS


  • Код


  • Задачи


  • Другие вопросы

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

Отредактировано 20.08.2020. изменения

JS


1. Есть многомерный массив глубиной N, который нужно сгладить. После сглаживания используйте его в качестве метода и привяжите к экземпляру объекта array.

Решение:

/**
* [1,2,[3,4]] -> [1,2,3,4]
*/

let arr = [1,2,[3,4, [5,6, [7, [8, 9, 10]]]]]

function flatten(arr) {
return arr.reduce(function(acc, next){
let isArray = Array.isArray(next)
return acc.concat(isArray ? flatten(next) : next)
}, [])
}

if (!Array.prototype.flatten) {
Array.prototype.flatten = function() {
return flatten(this)
}
}
console.log(arr.flatten());


2. Создайте промис с нуля

Решение:

class CustomPromise {
state = "PENDING"
value = undefined
thenCallbacks = []
errorCallbacks = []

constructor(action) {
action(this.resolver.bind(this), this.reject.bind(this))
}

resolver(value) {
this.state = "RESOLVED"
this.value = value
this.thenCallbacks.forEach((callback) => {
callback(this.value)
})
}

reject(value) {
this.state = "REJECTED"
this.value = value
this.errorCallbacks.forEach((callback) => {
callback(this.value)
})
}

then(callback) {
this.thenCallbacks.push(callback)
return this
}

catch (callback) {
this.errorCallbacks.push(callback)
return this
}
}

let promise = new CustomPromise((resolver, reject) => {
setTimeout(() => {
const rand = Math.ceil(Math.random(1 * 1 + 6) * 6)
if (rand > 2) {
resolver("Success")
} else {
reject("Error")
}
}, 1000)
})

promise
.then(function(response){
console.log(response)
})
.catch(function(error){
console.log(error)
})


3. Отфильтруйте список фильмов по среднему рейтингу, названию. Отсортируйте отфильтрованный список по любому полю.

Решение:

// O(M)
function getMovies() {
return []; // [{id, name, year}]
}

// O(R)
function getRatings() {
return []; // [{id, movie_id, rating}] 0 / e.g 9.3
}

/**
* minAvgRating ->
* avgRating >= minAvgRating
*
* sort ->
* name -> ascending order movies by name
* -name -> descending
*
* avgRating
*
*
* search ->
* 'ave' -> 'Avengers'
* 'avengers' -> 'Avengers'
* 'AvengersInfinitywar' -> 'Avengers'
*/
const toLower = str => str.toLocaleLowerCase()

const getAvrgRating = (movie, movingWithRatings) => {
let count = 0;
return movingWithRatings.reduce((acc, value, index) => {
const movieMatch = movie.id === value.movie_id
if (movieMatch) {
acc+=value.rating
count++
}
if (index === movingWithRatings.length - 1) {
acc = acc/count
}
return acc
}, 0)
}

const isSubString = (str1, str2) => {
str1 = toLower(str1.split(" ").join(""))
str2 = toLower(str2.split(" ").join(""))
if (str1.length > str2.length) {
return str1.startWith(str2)
} else {
return str2.startWith(str1)
}
}

const moviesList = getMovies()
const movingWithRatings = getRatings();
function queryMovies({ search, sort, minAvgRating }) {
let filteredMovies = movingWithRatings.filter(movie => getAvrgRating(movie, movingWithRatings) >= minAvgRating);
filteredMovies = filteredMovies.map(movie => moviesList.filter(listItem => listItem.id === movie.movie_id).pop())
filteredMovies = filteredMovies.filter(movie => isSubString(toLower(movie.name), toLower(search)))
filteredMovies = filteredMovies.sort((a, b) => {
const isDescending = sort[0] === '-' ? true : false
let sortCopy = isDescending ? sort.slice(1) : sort
const value1 = a[sortCopy]
const value2 = b[sortCopy]
if (isDescending) {
return value1 > value2 ? -1 : 1
}else {
return value1 < value2 ? -1 : 1
}
})
filteredMovies = filteredMovies.map(movie => ({
...movie,
avgRating: movingWithRatings.filter(ratedMovie => ratedMovie.movie_id === movie.id)[0].rating
}))
return filteredMovies
}


4. Загрузите все публикации и комментарии по URL-адресу конечной точки. Выполните следующее.


  • Соотнесите все комментарии с публикациями, к которым они относятся. В результате данные должны иметь следующую структуру.



//service.js
const POSTS_URL = ` `;
const COMMENTS_URL = ` `;

export const fetchAllPosts = () => {
return fetch(POSTS_URL).then(res => res.json());
};

export const fetchAllComments = () => {
return fetch(COMMENTS_URL).then(res => res.json());
};


import { fetchAllPosts, fetchAllComments } from "./service";



const fetchData = async () => {
const [posts, comments] = await Promise.all([
fetchAllPosts(),
fetchAllComments()
]);

const grabAllCommentsForPost = postId =>
comments.filter(comment => comment.postId === postId);

const mappedPostWithComment = posts.reduce((acc, post) => {
const allComments = grabAllCommentsForPost(post.id);
acc[post.id] = allComments;
return acc;
}, {});

console.log("mappedPostWithComment ", mappedPostWithComment);
};

fetchData();


5. Реализуйте метод getHashCode в экземпляре объекта string. Метод должен быть доступен для всех строк.

Решение:

let s1 = "sample"

if (!String.prototype.getHashCode) {
String.prototype.getHashCode = function(){
console.log('String instance ', this)
return this
}
}


6. Какой результат будет у приведенных ниже выражений?

1+true
true+true
‘1’+true
‘2’ > ’3’
‘two’>’three’


Решение:

2
2
1true
false
true

7. Реализуйте методы bind и reduce.

Решение:

//bind
if (!Function.prototype.bind) {
Function.prototype.bind = function(...arg){
const func = this
const context = arg[0]
const params = arg.slice(1)
return function(...innerParam) {
func.apply(context, [...params, ...innerParam])
}
}
}

//reduce
Array.prototype.reduce = function(func, initState) {
const arr = this
const callback = func
let init = initState

arr.forEach(function(value, index){
init=callback(init, value)
})
return init
}


8. Реализуйте функцию debounce

Решение:

const debounce = function(func, interval) {
let timerId;
return function(e){
clearTimeout(timerId)
timerId = setTimeout(function(){
func.apply()
}, interval)
}
}
debounce(apiCall, 3000)


9. Реализуйте функцию throttle

Решение:

const throttle = (callback, interval) => {
let timerId;
let allowEvents = true;

return function() {
let context = this;
let args = arguments;

if (allowEvents) {
callback.apply(context, args)
allowEvents = false;
timerId = setTimeOut(function(){
allowEvents = true
}, interval)
}
}
}


10. Создайте механизм опроса для API. Вызов API выполняется через заданные интервалы. Это API фондового рынка, который должен получать обновленные данные о котировках. После получения результатов отразите их в пользовательском интерфейсе.

Нужно описать свой подход к решению, код писать не нужно. Возможны разные варианты решения.

Решение:

//С использованием метода setInterval, декоратора throttle и флагов
setInterval=>Endpoint=>Render

//с инверсией управления
//Endpoint=>Render=>setTimeout=>Endpoint=>Render=>SetTimeout...

11. Конвертируйте этот код, основанный на наследовании классов, в ES5.

class Parent(name){
constructor(name) {
this.name=name
}

getName(){return this.name}
}

class Children extends Parent {
constructor(props){
super(props)
}
}

Решение:

function Parent(name) {
this.name = name
}

Parent.prototype.getName = function() {
return this.name
}

function Children(name){
Parent.call(this, name)
}

Children.prototype = new Parent()


12. Что выведет следующий код?

//Q.1
var x = 1;
var y = x;

x = 0;
console.log(x, y);

//Q.2
var x = [1];
var y = x;

x = [];
console.log(x,y);

//Q.3
function Abc() { console.log(this); };
Abc()
new Abc();

//Q.4
var x = 1;
var obj = {
x: 2,
getX: function () {
return console.log(this.x);
}
};

obj.getX()
let a = obj.getX
console.log(a)

//Q.5
//Как вывести 2 с использованием переменной a в коде из предыдущего вопроса?

//Q.6
console.log("A");
setTimeout(() => console.log("B"), 0);
setTimeout(() => console.log("C"), 0);
console.log("D");

//Q.7
setTimeout(function() {
console.log("A");
}, 0);
Promise.resolve().then(function() {
console.log("B");
}).then(function() {
console.log("C");
});

console.log("D");

//Q.8
let obj1 = {
a:1,
b:2
}

function mutate(obj) {
obj = {a:4, c:6}
}

console.log(obj1)
mutate(obj1)
console.log(obj1)


Решение:

//A.1
0 1

//A.2
[] [1]

//A.3
Будет выведен объект window

//A.4
Будут выведены значения 2 и 1

//A.5
a.call(obj);

//A.6
A, D, B , C

//A.7
D, B, C, A

//A.8
{ a: 1, b: 2 }
{ a: 1, b: 2 }

13. Есть массив чисел. Выведите следующие элементы.

const list = [1,2,3,4,5,6,7,8]
const filteredArray = list.filter(between(3, 6)) // [4,5]

Решение:

function between(start, end) {
return function (value,index) {
return value>start && valuecode>
Алгоритмы


1. Рассмотрите последовательность.

A := 1
B := A*2 + 2
C := B*2 + 3 и так далее...

Напишите программу, которая :


  • выводит число, соответствующее определенной букве;


  • для строки, например 'GREP', вычисляет сумму чисел, соответствующих буквам строки (т. е. G + R + E + P) из этой последовательности;


  • и находит самую короткую строку, соответствующую большому числу (не больше максимального 32-разрядного целого числа).

Для решения последней задачи можно использовать жадный алгоритм. Числовые значения, соответствующие буквам, должны рассчитываться по мере необходимости. НЕ НУЖНО вычислять их заранее и сохранять в структуре данных.

Решение:

//A = 1
//B = A*2 +2
//C = B*2+ 3
//D = C*2+ 3

var genCharArray = function(charA, charZ) {
var a = [], i = charA.charCodeAt(0), j = charZ.charCodeAt(0);
for (; i 1){
var charTotalSequence = input.split("").reduce(function(acc, curr){
return acc + charSequence(charMap[curr]);
},0);
console.log(charTotalSequence);
}

2. Найдите в массиве пару чисел, сумма которых равна заданному числу.

Решение:

let nums = [2, 7, 10, 1, 11, 15, 9]
let target = 11
let numsMap = new Map()
let pairs = nums.reduce((acc, num) => {
let numToFind = target - num
if (numsMap.get(numToFind)) {
return [...acc, [num, numToFind]]
} else {
numsMap.set(num, true)
return [...acc]
}
}, [])

console.log("Pairs ", pairs)

3. Найдите локальный максимум в заданном массиве. Локальный максимум — это элемент, значение которого превышает значения элементов, расположенных справа и слева от него. Я использовал нотацию O(n). Это очевидное решение, которое можно оптимизировать.

Решение:

let x = [1, 2, 3, 5, 4] //Результаты: 5
if x.length == 1 return x[0]
else
let i = 1
for(;i x[i+1] return x
}
if x.length - 1 == i return x

4. Поверните матрицу на 90 градусов по часовой стрелке. Решение должно выполняться в памяти, содержащей входные данные (алгоритм in-place, «на месте»).



Решение:

[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
//Сначала транспонируем матрицу.
//После транспонирования матрица будет выглядеть так.
[
[1, 4, 7],
[2, 5, 8],
[3, 6, 9]
]
//Теперь остается всего лишь изменить порядок элементов массива на обратный.
//В результате матрица будет выглядеть так.
[
[7, 4, 1],
[8, 5, 2],
[9, 6, 3]
]
//Первоначальная матрица развернута на 90 градусов.

5. Максимальная сумма подмассивов по модулю M.



6. Найдите в массиве три элемента, сумма которых равна заданному числу.

Решение:

let x = [1, 2, 3, 4, 5]
let target = 7
let found = []

const twoPointer = (l ,r, current) => {
while(l target) {
r--
} else {
l++
}
}
}

const threeSum = (x, target) => {
for (let i=0;icode>

7. Есть строка и целое число k. Вычислите количество подстрок, в которых каждый уникальный символ встречается ровно k раз.



Решение:

const subStrHasSameCharCount = (str, startIndex, endIndex, totalHop) => {
let charMap = {}
for (let k=startIndex;k 0
return totalCount ? Object.values(charMap).every(item => item == totalHop) : false
}


const characterWithCountK = (str, k) => {
if (k == 0) return ''
let count = 0
let initialHop = k
while (initialHop < str.length) {
for (let j=0;j str.length) continue
count = subStrHasSameCharCount(str, startIndex, endIndex, k)
? count + 1: count
}
initialHop+=k
}
count = subStrHasSameCharCount(str, 0, initialHop, k)
? count + 1: count
return count
}


let str = 'aabbcc'
let k = 2
console.log(characterWithCountK(str, k))


8. Есть две строки — s1 и s2, каждая из которых содержит символы от a до z в разном порядке. Проверьте, можно ли переставить символы в строке s1 таким образом, чтобы строки стали равными.

Решение:

let s1 = 'dadbcbc'
let s2 = 'ccbbdad'
let charMap = {}

const canBeRearranged = (s1, s2) => {
if(s1.length!==s2.length){
return false
}
for(let i=0;icode>

9. Есть массив с переменной начальной длиной. Расположите элементы массива в случайном порядке.

Решение:

const swap = (index1, index2, arr) => {
let temp = arr[index1]
arr[index1] = arr[index2]
arr[index2] = temp
}

const shuffle = (arr) => {
let totalLength = arr.length
while(totalLength > 0) {
let random = Math.floor(Math.random() * totalLength)
totalLength--
swap(totalLength, random, arr)
}
return arr
}


let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
arr = shuffle(arr)

10. Вычислите сумму всех элементов многомерного массива с бесконечной глубиной.

Решение:

let arr = [4, 5, 7, 8, [5, 7, 9, [3, 5, 7]]]
let sum = 0

const calculateSum = (arr) => {
arr.reduce(function(acc, currentVal) {
const isEntryArray = Array.isArray(currentVal)
if (isEntryArray) {
return acc.concat(calculateSum(currentVal))
} else {
sum+=currentVal
return acc.concat(currentVal)
}
}, [])
}
calculateSum(arr)
console.log(sum)


11. Сгладьте многоуровневый вложенный объект.

Решение:

const obj = {
level1: {
level2: {
level3: {
more: 'stuff',
other: 'otherz',
level4: {
the: 'end',
},
},
},
level2still: {
last: 'one',
},
am: 'bored',
},
more: 'what',
ipsum: {
lorem: 'latin',
},
};

var removeNesting = function(obj, parent){
for (let key in obj){
if (typeof obj[key] === "object") {
removeNesting(obj[key], parent+"."+key)
} else {
flattenedObj[parent+'.'+key] = obj[key]
}
}
}

let flattenedObj = {}
const sample = removeNesting(obj, "");
console.log(flattenedObj);

12. Есть данные в формате json, где каждый объект обозначает каталог и может, в свою очередь, содержать другой вложенный объект. Выведите на экран структуру каталога.



13. Есть массив объектов, содержащих информацию о сотрудниках (у каждого сотрудника есть несколько подчиненных). На основании этих данных постройте иерархию сотрудников.

Решение:

const employeesData = [{
id: 2,
name: 'Андрей (главный технический директор)',
reportees: [6]
}, {
id: 3,
name: 'Алексей (главный операционный директор)',
reportees: []
}, {
id: 6,
name: 'Александр (руководитель инженерной группы)',
reportees: [9]
}, {
id: 9,
name: 'Анатолий (старший инженер)',
reportees: []
}, {
id: 10,
name: 'Антон (генеральный директор)',
reportees: [2, 3],
}];

/*
A (генеральный директор)
----B (главный технический директор)
--------D (руководитель инженерной группы)
------------E (старший инженер-разработчик)
----C (главный операционный директор)
*/

const findCeo = (currentEmp) => {
let parentEmployee = employeesData.filter(emp => emp.reportees.indexOf(currentEmp.id) > -1)
if (parentEmployee && parentEmployee.length > 0) {
return findCeo(parentEmployee[0])
} else {
return currentEmp
}
}

const logHierarchy = (currentEmp, indent) => {
console.log("-".repeat(indent) + currentEmp.name)
indent+=4;
for(let i=0;i emp.id === currentEmp.reportees)
logHierarchy(employee[0], indent)
}
}

const traverse = (employee) => {
let ceo = findCeo(employee)
logHierarchy(ceo, 0)
}

traverse(employeesData[0])

14. Преобразуйте заданную матрицу в спиральную и выведите на экран

const inputMatrix = [
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11,12,13,14,15],
[16,17,18,19,20],
]

const exprectOutput = [1,2,3,4,5,10,15,20,19,18,17,16,11,6,7,8,9,14,13,12]

Решение:

function spiralParser(inputMatrix){
const output = [];
let rows = inputMatrix.length;
let cols = rows > 0 ? inputMatrix[0].length : 0;

//singleEmptyRow => Edge case 1 //[]
if (rows === 0) {
return []
}

if (rows === 1) {
//singleElementRowNoCol => Edge case 2 //[[]]
if (cols === 0) {
return []
} else if (cols === 1){
//singleElementRow => Edge case 3 //[[1]]
output.push(inputMatrix[0][0])
return output
}
}

let top = 0;
let bottom = rows - 1;
let left = 0;
let right = cols - 1;
let direction = 0;
//0 => left->right
//1 => top->bottom
//2 => right->left
//3 => bottom->top

while(left /left->right
for (let i=left; i/top->bottom
for (let i=top; i/right->left
for (let i=right; i>=left;i--) {
output.push(inputMatrix[bottom])
}
bottom--
} else if (direction === 3) {
//bottom->top
for (let i=bottom; i>=top;i--) {
output.push(inputMatrix
)
}
left++
}
direction = (direction + 1) % 4
}
return output;
}

console.log(spiralParser(inputMatrix2))

15. Найдите символ с максимальным количеством последовательных вхождений в заданной строке.

let str = 'bbbaaaaccadd'; //Больше последовательных вхождений (4) у символа a

Решение:

//псевдокод
maxNow = если длина входной строки равна1 или больше 1 ? 1 : 0
maxOverall = если длина входной строки равна1 или больше 1 ? 1 : 0

для символов входной строки с индексом 1 и больше
если символ равен предыдущему символу
maxNow++ //увеличить на 1
maxOverall = max(maxOverall, maxNow)
иначе если символ не равен предыдущему символу
maxNow = 1

16. Есть массив переменной длины. Переместите все двойки (2) в конец массива.

let inputArr = [2,9,1,5,2,3,1,2,7,4,3,8,29,2,4,6,54,32,2,100]
//ouput => [9,1,5,3,1,7,4,3,8,29,4,6,54,32,100,2,2,2,2,2]

Решение:

let slowRunner = 0

for (let fastRunner=0;fastRunnercode>

17. Выведите список в обратном порядке

//На входе = 1 -> 2 -> 3 -> 4 -> 5 -> 6
//В результате = 1 code>

Решение:

//псевдокод
let current = head
let prev = null
let next = null

while(current) {
next = current.next
current.next = prev
prev = current
current = next
}

18. Реализуйте прямой обход дерева с помощью итераций (без рекурсии)

Решение:

//псевдокод
const preorder = (root) => {
let stack = []
stack.push(root)

пока(переменная stack содержит данные) {
let current = stack.pop()
console.log(current.value)
if (current.right) {
stack.push(current.right)
}
if (current.left) {
stack.push(current.left)
}
}
}
Задачи


1. Разработайте систему для автоматизации парковки, отвечающую следующим требованиям.


  • Она хранит данные об N автомобилях. Она обрабатывает данные о наличии парковочных мест.


  • Она регистрирует въезжающие и выезжающие автомобили.


  • Автоматизированная система учета автомобилей регистрирует все въезжающие и выезжающие автомобили по следующим данным: регистрационный номер, цвет, парковочное место.

Система должна предоставлять следующую информацию:


  • регистрационные номера всех автомобилей определенного цвета;


  • номер парковочного места автомобиля по регистрационному номеру;


  • парковочные места автомобилей определенного цвета.


  • список свободных парковочных мест.

Требования:


  • для структурирования кода можно пользоваться классами/структурами;

  • решение должно быть расширяемым для последующего применения.

Некоторые принципы разработки кода:


  • модульность кода;


  • соглашения об именовании;


  • принципы SOLID.



2. Создайте React-компонент Ping, при использовании которого API будет отправлять запрос по заданному URL. Если возвращается код состояния 200, это означает, что пользователь в Сети. Если возвращается любой другой код состояния, это означает, что пользователь не в Сети.

Попробуйте изменить статус из сетевой панели dev tools.



3. Создайте конструктор динамических форм на базе json. Формы должны группироваться по id. В каждой группе может быть другая вложенная группа.



4. Создайте на чистом JavaScript простейший лист Excel, в котором можно добавлять и удалять строки и столбцы. На решение этой задачи отводилось 40 минут.



5. Создайте строку поиска по списку пользователей.

Объект user (пользователь) включает следующие поля.

id: уникальный идентификатор
имя: имя пользователя
товары: список товаров, заказанных пользователем
адрес: адрес пользо
индекс: почтовый индекс пользователя

Поиск должен осуществляться по всем полям.

Результаты поиска должны выводиться в виде карточки пользователя.

Требования:
Когда пользователь начинает вводить символы в строку поиска, появляется выпадающий список. Поиск может осуществляться по строке.

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

(Навигация будет осуществляться с помощью клавиатуры, если мышь наведена на элемент списка. Если клавиатура не используется, навигация будет осуществляться с помощью мыши.)

Это похоже на принцип поиска в YouTube

Если результаты не найдены, выводится пустая карточка.
Список карточек должен прокручиваться.

Подсвеченная карточка (с помощью клавиатуры или мыши) появляется в области просмотра полностью.



Другие вопросы


1. Как бы вы структурировали интерфейсное приложение?
2. Реализуйте стратегию ленивой загрузки
3. Что такое серверный рендеринг?
4. Как развернуть React-приложение в промышленной среде?
5. Что такое сервис-воркер (веб-воркер)?
6. Как оптимизировать веб-приложение и повысить его производительность?
7. Расскажите о стратегиях кэширования на стороне клиента.
8. Что такое CORS?
9. Назовите компоненты высшего порядка в React.
10. Как работает функция connect в Redux?
11. Что такое PureComponent в React?

Ресурсы




Узнать подробно о курсе:









 
Сверху Снизу