Привет! Сегодня я расскажу вам, как можно использовать отладчик для решения, на мой взгляд, нетривиальной проблемы JavaScript. В JavaScript объекты представляют собой составной тип данных; их значение передается по ссылке.
Другими словами, когда мы передаем объект функции в качестве параметра или где угодно, мы можем изменить его свойства.
Использование инструкции, состоящей из выражения для переменной, хранящей ссылку, а также операторов точки и присваивания.
После этого другие инструкции, которые работают или будут работать с этой переменной/параметром, получат изменение свойства по ссылке.
Зачастую такое поведение повреждает пользовательские данные, приводит к ошибкам и является нежелательным.
Поиск источника таких нежелательных изменений свойств может занять много времени: программа уже может быть большой и состоять из сотен тысяч инструкций.
Давайте посмотрим на простой пример.
Сейчас веб-программа не работает, так как в консоли ошибка и не выводится полное имя.<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Debug property mutation example</title> <script> const user = { firstName: 'Vasilij', middleName: 'Alibabaevich', lastName: 'Radner', aka: 'Alibaba', getFullName() { return `${this.lastName} ${this.firstName.slice(0, 1)}.
${this.middleName.slice(0, 1)}.
` } }; </script> <script src="object-property-mutation.js" type="application/javascript"></script> </head> </head> <body> <script> Promise.resolve(user).
then(user.getFullName.bind(user)).
then(console.log); </script> </body> </html>
Читаем верхнее сообщение в консоли: Uncaught (in promise) TypeError: Cannot read property 'slice' of undefined
Ошибка типа не обработана (в обещании): невозможно прочитать фрагмент свойства из неопределенного.
Нажмите на ссылку и перейдите к месту ошибки.
getFullName() {
return `${this.lastName} ${this.firstName.slice(0, 1)}.
${this.middleName.slice(0, 1)}.
`
}
Мы видим, что выражение ошибочно this.firstName.slice(0, 1)
состоит из четырех операторов: два точечных оператора
один оператор-разделитель-запятая
один оператор группировки — пара круглых скобок
Давайте прочитаем инструкцию.
Левое выражение вычисляется первым this.firstName
Он состоит из оператора точки, основного выражения this слева и идентификатора firstName справа.
Результат этого выражения будет неопределенным.
Выполнение следующего оператора точки вызывает ошибку.
Поскольку оператор точки работает только с типами объектов, его выполнение из неопределенных результатов приводит к ошибке — я не могу получить свойство среза из неопределенных.
Оказывается, где-то этому свойству было присвоено неопределенное значение.
Чтобы решить эту проблему, попробуем сделать наоборот. Давайте воспользуемся инструментом отладки остановиться на исключении .
Двигаясь вниз по стеку вызовов от места ошибки, попробуем перейти к инструкции, которая изменила свойство.
Выбор инструмента остановки при исключении
Мы видим, что в стеке всего два вызова.
Перейдем к предыдущему звонку.
Мы видим, что нет явной инструкции, изменяющей свойство firstName.
Делаем вывод, что в этом стеке вызовов изменений не происходит.
Как вам это нравится?
И как найти злодея, который изменил свойство моего объекта? Напишите, пожалуйста, в комментариях, как бы вы его нашли? Ребята, кто со мной работает и кому я это рассказал, напишите, пожалуйста, звездочку в комментарии.Мне очень интересно услышать, как другие специалисты по JavaScript решают подобные проблемы.
Знаете, когда я впервые столкнулся с таким поведением JavaScript, я потратил пару часов на изучение и вырвал клок волос из своей челки.
Отключите инструмент «Пауза при исключении».
Итак, вот наш новый план: мы определим свойство firstName в объекте пользователя, используя методы получения и установки.
Давайте добавим в установщик инструкцию отладки, используя оператор отладчика и оператор точки с запятой.
const user = {
_firstName: 'Vasilij',
set firstName(value) {
debugger;
this._firstName = value;
},
get firstName() {return this._firstName},
middleName: 'Alibabaevich',
lastName: 'Radner',
aka: 'Alibaba',
getFullName() {
return `${this.lastName} ${this.firstName.slice(0, 1)}.
${this.middleName.slice(0, 1)}.
`;
}
};
Двигаясь дальше по стеку вызовов, мы находим инструкцию, которая изменяет свойство firstName.
Отладчик остановился на установщике до того, как новое значение было записано в объект.
Мы видим, что значение параметра value не определено.
Теперь, используя стек вызовов, мы можем легко перейти к предыдущему вызову.
иаааа победа, ура.
Есть еще более простой способ решить эту проблему с помощью инструмента отладки.
остановиться на исключении .
Вот наш новый план: сделать объект пользователя не объектом и с помощью инструмента остановка исключения , мы легко получим ошибочные инструкции.
Так как мы знаем, что при попытке получить свойство из undef возникает ошибка.
Мы включаем инструмент остановки при исключении и присваиваем значение undef пользовательской переменной.
const user = undefined;
Мы снова остановились на точке повреждения свойства firstName.
Это все, что я хотел вам сегодня рассказать об отладке нежелательных изменений объектов.
Спасибо за прочтение статьи.
Ставьте лайк, подписывайтесь на канал, делитесь этим видео и статьей с друзьями, всего доброго.
github.com/NVBespalov/js-lessons/tree/error/property-mutation Теги: #JavaScript #отладка #отладка #инструменты отладки