, чтобы сохранить свой прогресс
Очень интересный урок, который хотелось бы обсудить... К своему удивлению, я не нашел здесь во всех уроках по Javascript уроков, касающихся методов типа Array.find(), Array.filter(), Array.findIndex() и т.п. При этом это очень полезные методы, используемые чуть ли не каждый день. И на мой взгляд они, во-первых, более короткие, чем конструкции типа for(...), а во-вторых, более логичны в плане восприятия.
Сразу отмечу, что я не хочу сказать, что другие решают не правильно. Я просто хочу показать другие варианты.
Сравним код большинства ответов в этой задаче:
и одно из моих решений:
Какое решение вам кажется более наглядным?
Как мне кажется, вариант с перечислением for (let i = 0; i < contacts.length; i++) более громоздкий и в нем больше отвлекающих переменных. То есть мы создаем переменную-счетчик i, сравниваем ее со значением длины массива, каждую итерацию увеличиваем ее значение, используем для получения элемента массива и т.п., и все это вместо того, чтобы работать просто с массивом и его элементами.
В моем варианте используется метод массива find(condition). Уточню, что прототипом всех массивов является Array. Соответственно, все методы его наследуются и конечным массивам. Метод find(condition) принимает в качестве параметра функцию, используемую для поиска элемента в текущем массиве (первого, удовлетворяющего условию). То есть массив перечисляет все свои элементы до тех пор, пока применяемая к ним функция не вернет истину (или то, что может быть преобразовано в логическое true). В моем случае это n => n.firstName === name.
Для кого-то данная конструкция может быть не понятна, уточню: это стрелочная функция. Если переводить на более понятный синтаксис, то это так:
Итак, применив метод Array.find() вместо перечисления for(...) я попытался найти нужный мне элемент.
const item = contacts.find(n => n.firstName === name);
В данном случае (если понять синтаксис) все сильно понятней и логичней: я выполнил метод поиска у самого массива и получил найденный элемент из него и присвоил в переменную item (или присвоил undefined, если элемент не был найден).
Далее я уже работаю с проверками на самом элементе
То есть вроде тоже все понятно: если элемент item есть, то в нем проверяю значение, если нет, то возвращаю сообщение об ошибке. И никаких лишних i и т.п.
В погоне за сокращением можно и вовсе вот так написать:
То есть я сразу проверил есть ли объект и если нет, возвращяю 'No such contact', иначе возвращаю свойство объекта (если оно есть) или сообщение 'No such property'
Да, такой стиль может показаться более сложным и запутанным, но сейчас чаще именно так и пишут, потому что меньше кода - меньше над чем думать приходится.
Если правильно понимаю - и по времени быстрее должно работать?
Совершенно не факт. Нужно тестирование проводить. Хотя вряд ли разница будет ощутимая. Но есть разница в восприятии и объеме кодовой базы.
Николай, сейчас более детально буду изучать предложенный тобой метод, но хотел бы уточнить пока по своему варианту решения - почему я получаю "Unspecified AssertionError" в первой и третьей проверке, не могу увидеть свою ошибку
Денис, у тебя здесь главная ошибка в том, что ты при первом же несовпадении контакта возвращаешь 'No such contact'. То есть по сути у тебя логика будет работать только для первого в массиве контакта и только если свойство есть. Но у тебя же и другие контакты проверяются. А как до них дойдет логика? В данном случае никак. То есть тебе надо перечислить все контакты и только если перебрал все и не нашел ни одного по имени, тогда только возвращать ошибку, то есть вынести это условие за пределы цикла. Если в цикле отработает целевое условие и ты выполнишь return - тогда и не дойдет дело до возврата ошибки. А если в цикле ничто не выполнится, тогда уже вернешь ошибку.
Второй момент: ты сразу первым делом проверяешь двойное условие
Не надо так. Первое главное условие у тебя: это найден контакт или нет. Если найден, тогда по нему уже все и проверяй далее. Если нет - то пропусти его. То есть оберни все в условие
Третий момент: старайся не использовать нестрогое сравнение ==, старайся всегда строгое ===. Иначе не редко будешь ловить логические ошибки.
Николай, огромное спасибо за супер подробный ответ
Не за что!
Согласен на счет метода. Здесь описание по лучше: https://doka.guide/js/array-find/
Почему такой код не работает? Логика - сначало проверить на отсутствие свойства с именем атрибута name. Если иначе - выполняется else if (изначально я вообще хотел там написать просто contacts[i].hasOwnProperty(prop) без && и проверки на наличие свайства с именем атрибута name). В этом коде почему-то работает только return "No such contact" и return "No such property".
function lookUpProfile(name, prop) {
for (let i = 0; i < contacts.length; i++) {
if (contacts[i].firstName != name) {
return "No such contact";
} else if (contacts[i].firstName == name && contacts[i].hasOwnProperty(prop)) {
return contacts[i][prop];
}
else return "No such property";
}
}
И еще хотел спросить: Так что в итоге находиться тут в переменной item: const item = contacts.find(n => n.firstName === name)? И что подставляется в переменную n? В n - gоочередно каждый объект массива contacts (которых по сути 4)? А item - становится найденным объектом (то есть при name "Akira" как я понял - это будет первый объект нашей базы данных, которая в массиве)? И уже там, внутри первого объекта, который занял переменную item мы начинаем искать prop далее через if'ы? И если это так, то как сделать аналогичную вещь, которая бы искала значение во внутренних массивах? Например если бы name было массивом, то как сделать такой find? const item = contacts.find(n => n.likes === name) - Так что ли?
Вот что я имею ввиду. Но почему-то это не работает.
let x = ["Pizza", "Coding", "Brownie Points"];
function lookUpProfile(name) {
var contact = contacts.find(item => item.likes == name);
if (contact) {
return contact;
}
return "Dont work";
}
console.log(lookUpProfile(x));
А это работает:
let x = "Akira";
function lookUpProfile(name) {
var contact = contacts.find(item => item.firstName == name);
if (contact) {
return contact;
}
return "Dont work";
}
console.log(lookUpProfile(x));
> В этом коде почему-то работает только return "No such contact" и return "No such property".
Посмотрите внимательно чужие решения. Они сводятся к тому, чтобы сначала найти контакт по имени в цикле, и только если найден контакт, тогда уже смотреть в нем свойства. А за пределами цикла, если не найден контакт, тогда уже только возвращать конечное решение "Контакт не найден". Вы же делаете иначе - вы сразу смотрите тот это контакт или нет, и если не тот, то возвращаете ошибку. В итоге ваша логика может сработать только если первый контакт в массиве соответствует запрошенному и свойство запрошено корректно. В противном случае вы возвращаете ошибку и далее перебор в цикле уже не выполняется.
По второй части вопроса: советую уже сейчас вам начинать изучать TypeScript, вы тогда начнете быть более внимательным к типам. В целом вы идею правильно поняли с поиском по внутренним массивам, но нельзя сравнивать строку с массивом. Для примера ваше: item.likes == name.
item.likes здесь - массив, например ["Pizza", "Coding", "Brownie Points"], и вы его пытаетесь сравнить со строчным name. Нельзя так. Почти всегда будет ложь, ито, только потому что вы используете нестрогое сравнение ==. Если бы использовали строгое ===, то 100% было бы всегда ложь, потому что типы не совпадают.
В вашем случае, если бы вы хотели найти по элементу во вложенном массиве, то надо еще внутри искать по массиву, а не просто через сравнение. Пример.
var contact = contacts.find(item => item.likes.includes(name));
Только здесь надо понимать, что name здесь - не имя контакта, а именно элемент массива likes, то есть "Pizza", "Coding" или "Brownie Points".
Описание метода Array.includes смотрите здесь https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
Спасибо за ответ. Довольно сложновато это пока воспринимается. Очень мало-по малу мозг проходит перепрошивку.)))
Не за что!
Просто не останавливайтесь и учитесь дальше. Практика решает.