Очень интересный урок, который хотелось бы обсудить... К своему удивлению, я не нашел здесь во всех уроках по 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
Спасибо за ответ. Довольно сложновато это пока воспринимается. Очень мало-по малу мозг проходит перепрошивку.)))
Не за что! Просто не останавливайтесь и учитесь дальше. Практика решает.