Zrozum jak działa console.log w JavaScript

Używasz console.log do debugowania swojego kodu? Jeśli tak, zapraszam Cię na serię artykułów o debuggowaniu z obiektem console. Zobaczymy jak logować z console.log obiekt czy tablicę, aby otrzymać prawidłowe dane oraz jak dodać do console.log kolory i style. Omówimy różne ciekawe i mało znane zastosowania console.log oraz innych funkcji z obiektu Console. Pokażę Ci, jak efektywnie ich używać i jak ułatwić sobie nasze programistyczne życie. Może nawet uda Ci się zaskoczyć kogoś z Twojej z pracy?

Czym właściwie jest console w JavaScript?

W ferworze debugowania być może nie zauważyłaś bądź nie zauważyłeś, że console jest po prostu… obiektem, który jest dostępny globalnie. Najczęściej używaną funkcją tego obiektu to log(), ale zawiera on również wiele innych funkcji. Spójrz, jaką zawartość console wyświetli nam konsola przeglądarki:

Console to obiekt globalny

Obiekt console, którym posługujemy się w programach, pozwala na dostęp do Konsoli przeglądarki z poziomu kodu.

Obiekt console w JS pozwala na dostęp do konsoli przeglądarki

Warto pamiętać o tym, że jest to jedynie dostęp do konsoli przeglądarki. To, jak dokładnie zostanie dane polecenie wyświetlone, zależy od danej przeglądarki i jej konsoli. Na poniższej grafice zobaczysz, jak różne przeglądarki wyświetlają nieco inaczej wynik polecenia console.info(). A jest to tylko czubek góry lodowej. Szczególnie warto o tym pamiętać, gdy celowo zostawiamy jakieś logi na produkcji bo np. chcemy coś zakomunikować naszemu użytkownikowi. Przykład znajdziesz w artykule o dodawaniu do console.log styli.

console_img3
Console log w JS może pokazać w Chrome i innych przeglądarkach różne wyniki

Funkcja console.log i jej malutkie "pułapki"

Definicja podstawowego użycia funkcji console.log w JavaScript według dokumentacji wygląda następująco:

				
					console.log(obj1 [, obj2, ..., objN]);
				
			

Możemy podać w funkcji dowolną liczbę argumentów. Dane każdego z tych argumentów zostaną połączone razem i wyświetlone jednocześnie. Zobaczmy przykład:

				
					const str1 = "tekst1";
const str2 = "tekst2";
const num = 1;
const arr = ["arr1", "arr2"];
const obj = { key1: 1, key2: "2" };

console.log("logowanie: ", str1, str2, num, arr, obj)
				
			

Mogłoby się wydawać, że powstanie z tego nieczytelny wielki string. W rzeczywistości jednak poszczególne zmienne dodane do console log jako argumenty zostaną oddzielone spacją. Tablice i obiekty są wciąż możliwe do rozwinięcia.

Dodając do console.log zmienne jako argumenty możemy logować wiele elementów na raz

"Składanie" wiadomości w console.log

Poza listowaniem kolejnych zmiennych w console.log, możemy również skomponować samodzielnie stringa. Można to zrobić używając standardowych metod łączenia stringów np. używając symbolu +, czy w nowszej wersji JS ES2015 używając tzw. template strings. Spójrz poniżej na przykład:

				
					const str1 = "tekst1";
const str2 = "tekst2";

console.log("Wartość zmiennej 1: " + str1 + ", wartość zmiennej 2: " + str2);
// ES2015
console.log(`Wartość zmiennej 1: ${str1}, wartość zmiennej 2: ${str2}`);

// Oba polecenia dadzą taki sam wynik:
// Wartość zmiennej 1: tekst1, wartość zmiennej 2: tekst2
				
			

Przy takim samodzielnym „składaniu” wartości w stringu na podanych zmiennych wywoływana jest funkcja toString(). Oznacza to, że obiekty zostaną wyświetlone w konsoli jako [object Object], bo właśnie taki jest wynik wywołania funkcji toString() na obiekcie.

Poza tym, co również jest istotne przy debugowaniu, konsola wyświetli wszystkie wartości jednolicie jako string w jednym kolorze. Może wydawać się to dość błahym problemem, jednak tracimy w tym momencie orientację, czy np. dana wartość wyglądająca jak numeryczna jest faktycznie typu number czy typu string.

Efekty zamiany różnych zmiennych przekazanych do console.log w dane typu string

Jeśli w console.log chcesz wylogować jedynie nazwę i wartość zmiennej, możesz użyć skrótowego tworzenia obiektów, wprowadzonego w ES2015.

				
					const nazwa_zmiennej = "wartość_zmiennej";
console.log({ nazwa_zmiennej });
				
			

Powyższy zapis jest odpowiednikiem console.log({ nazwa_zmiennej: nazwa_zmiennej }). Dzięki temu otrzymujemy obiekt z nazwą zmiennej i jej wartością.

Logowanie z console.log nazwy i wartości zmiennej wykorzystując skrótową metodę tworzenia obiektów

Używasz console.log do logowania obiektów? To uważaj na pułapkę.

Logujesz zawartość obiektów poprzez console.log(obj)? To musisz uważać! Konsola w takim wypadku nie zawsze powie Ci prawdę!

Spójrzmy na poniższy przypadek:

				
					const obj = { key1: 1, key2: 2 };
console.log(obj);

// wiele linijek kodu później
obj.key2 = 3;
				
			

Jaki będzie wynik w konsoli? key2 w obiekcie będzie miał wartość 2 czy 3?

Odpowiedź nie jest wcale jednoznaczna i można powiedzieć, że.. to zależy 😉 Zobaczmy co otrzymamy w konsoli:

Gdy logujemy w console log obiekt, wartość tego obiektu może być inna po rozwinięciu go w konsoli

Na pierwszy rzut oka wszystko wygląda ok – w momencie wywołania funkcji console.log() klucz key2 miał wartość 2. Jednak po rozwinięciu obiektu wartość klucza key2 wynosi 3. Dlaczego?

W JS również do console.log obiekty są przekazywane przez referencję

W języku JavaScript wszystkie obiekty (a więc tablice też) przekazywane są przez referencję. Oznacza to, że nasza zmienna obj nie zawiera tak naprawdę wartości przypisanego obiektu, ale referencję do niego.

Kiedy modyfikujemy jakiś obiekt (w tym tablicę), to wartość naszej zmiennej jest automatycznie aktualizowana. Zanim obiekt w konsoli zostanie rozwinięty, będzie on pokazywał stan tego obiektu w momencie wywoływania console.log(). Jednak z chwilą rozwinięcia tego obiektu w konsoli wartość obj zostanie zewaluowana i pokazana zostanie aktualna, czyli zmodyfikowana wartość klucza key2.

Możesz pomyśleć, że właściwie to wystarczyłoby nie rozwijać obiektu 😉 Jednak w praktyce rzadko mamy do czynienia z tak prostymi konstruktami. Przy obiektach bardziej rozbudowanych nie ma możliwości aby zobaczyć jego wartość bez rozwijania go w konsoli. Problem pojawi się już przy zwykłej tablicy zawierającej jeden prosty obiekt. Spójrz na przykład:

				
					const arr = [{ peak: "Szrenica" }];
console.log(arr);

arr.push({ peak: "Sniezka" });
				
			

Zgodnie z tym co omówiliśmy powyżej, tablica w konsoli po rozwinięciu będzie zawierać oba obiekty, pomimo że „Śnieżka” została dodana już po wywołaniu funkcji console.log(). W tym przypadku jednak nie zobaczymy nic zanim nie rozwiniemy tablicy.

Wynik przekazania do console.log tablicy z obiektami

Jak rozwiązać problem logowania obiektu w console.log?

Na szczęście problem ten można dość łatwo rozwiązać. Omówimy dwa popularne rozwiązania, które pozwolą nam faktycznie dowiedzieć się, jak wyglądał nasz obiekt w momencie logowania.

Logowanie konkretnych wartości

Jednym z najprostszych rozwiązań tego problemu może być nie logowanie całych obiektów, a jedynie kluczy, które nas interesują. Oczywiście najlepiej, aby też były one wartościami typu prostego, a nie obiektami. Wtedy wartość w konsoli będzie faktycznie taka, jak w momencie wywołania funkcji console.log()

				
					const obj = { key1: 1, key2: 2 };
console.log(obj.key2); // <-- logowanie tylko konkretnego klucza

// wiele linijek kodu później
obj.key2 = 3;
				
			

Wynik w konsoli:

Zamiast całego obiektu możemy wylogować tylko konkretny klucz, który ma wartość typu prostego

Metoda JSON.stringify

Logowanie poszczególnych wartości obiektów nie zawsze jednak sprawdza się w praktyce i często najwygodniej jest nam logować całe obiekty.

Aby uniknąć pułapki związanej z tym, że obiekty w JS przekazywane są przez referencję, możemy w momencie logowania przekształcić taki obiekt w JSON za pomocą metody JSON.stringify(). Dzięki temu przekształceniu nie będziemy już logować do konsoli referencji do obiektu, a faktyczną jego wartość w momencie wywoływania funkcji console.log()

Spoójrzmy na poniższy przykład tablicy zawierającej obiekty.

				
					const peaks = [
  {
    name: "Skalnik",
    record_meta: {
      createdDate: 1614942811096,
      modifiedDate: 1614942835792
    }
  },
  {
    name: "Sniezka",
    record_meta: {
      createdDate: 1614942811096,
      modifiedDate: 1614942835792
    }
  }
];
				
			

Chcąc podejrzeć ten obiekt za pomocą console.log do funkcji przekażemy nie sam obiekt, tylko JSON.

				
					console.log(JSON.stringify(peaks));
				
			

Wynik w konsoli:

Wynik zastosowania na obiekcie metody JSON.stringify()

Tak przekształcony wynik jest już odporny na wszelkie późniejsze zmiany w naszym obiekcie i pokazuje jego wartość w momencie wywołania funkcji console.log(). Niestety przy bardziej rozbudowanych obiektach taki zapis może być zupełnie dla nas nieczytelny. Możemy więc nadać mu nieco formatowania:

				
					console.log(JSON.stringify(peaks, null, 2));
				
			

Dzięki temu dodamy do wyniku wcięcie 2 spacji i stanie się on dużo bardziej czytelny. Więcej o możliwościach JSON.stringify() możesz poczytać w dokumentacji.

Wynik zastosowania na obiekcie metody JSON.stringify() z dodatkowym formatowaniem

Duże obiekty JSON są mało czytelne

Wadą tego rozwiązania, szczególnie przy większych strukturach, jest to, że wszystkie zagnieżdżone obiekty są od razu pokazywane w formie rozwiniętej. Poza tym znowu tracimy kolorowanie wartości ze względu na swój typ, co czasem bywa pomocne.

Oba te problemy możemy rozwiązać poprzez ponowną konwersję danych typu JSON w obiekt. Odzyskamy dzięki temu wszystkie zalety bezpośredniego logowania obiektu do konsoli bez ryzyka odnoszenia się do referencji tego obiektu. Do zamiany JSON w obiekt wykorzystamy funkcję JSON.parse().

				
					console.log(JSON.parse(JSON.stringify(peaks)));
				
			

Oto co otrzymamy w konsoli:

Wynik logowania w console.log obiektu z użyciem funkcji JSON.stringigy() i JSON.parse()

Ponownie mamy więc do dyspozycji ładnie sformatowany obiekt, który możemy rozwijać według naszych potrzeb. Dzięki zastosowaniu funkcji JSON.stringify() wynik w konsoli jest teraz odporny na wszelkie mutacje obiektu, które mogą się odbywać w kolejnych linijkach. Możesz to sprawdzić dodając nową wartość do tablicy już po wywołaniu funkcji console.log.

				
					const peaks = [
  {
    name: "Skalnik",
    record_meta: {
      createdDate: 1614942811096,
      modifiedDate: 1614942835792
    }
  },
  {
    name: "Sniezka",
    record_meta: {
      createdDate: 1614942811096,
      modifiedDate: 1614942835792
    }
  }
];

console.log(JSON.parse(JSON.stringify(peaks)));


peaks.push({
  name: "Szrenica",
  record_meta: {
    createdDate: 1614942811096,
    modifiedDate: 1614942835792
  }
});
				
			

Jak się przekonasz, nasz pięknie wylogowany obiekt nie będzie zawierał obiektu z name "Szrenica". Możesz sprawdzić to u siebie w przeglądarce.

Elementy DOM w console.log loguj z JSON

Dzięki takiemu rozwiązaniu możesz też łatwiej wychwycić błędy związane z elementami DOM. Elementy te, tak samo jak wszystkie obiekty, przekazywane są do console.log przez referencję. Z tego właśnie powodu może wystąpić sytuacja, kiedy to funkcja wywołana na nieistniejącym jeszcze elemencie DOM (null) spowoduje błąd, ale przy próbie logowania go do konsoli wydaje się nam, że pozornie wszystko jest w porządku. W takiej sytuacji użycie funkcji JSON rozwiążę problem i pokaże Ci, jak faktycznie wygląda ten element w momencie, kiedy go logujesz.

Podsumowanie

Mam nadzieję że po przeczytaniu tego artykułu logowanie z console log obiektów (w tym tablic) będzie już dla Ciebie dużo bardziej przewidywalne. Teraz dokładnie będziesz wiedzieć, czego możesz się spodziewać w konsoli po zastosowaniu takich czy innych metod. Jeśli zauważysz, że console log nie działa tak, jak tego oczekujesz, to łatwiej będzie Ci zrozumieć, co może być przyczyną.

Jeśli chcesz zobaczyć, co jeszcze potrafi konsola, to koniecznie zobacz kolejny artykuł z serii, tym razem o wykorzystaniu substitution strings w console log.

Wartościowe materiały prosto na Twoją skrzynkę mailową

Zapisz się do newslettera i nie przegap kolejnych artykułów, które pogłębią Twoją wiedzę o Java Script. Absolutne zero spamu.

Uzupełniając powyższe pole wyrażam zgodę na zapis do newslettera, aby otrzymać więcej materiałów i ciekawych linków z portalu javascriptbeztajemnic.pl. Zero spamu. Mogę w każdej chwili wycofać zgodę zgodnie z Polityką Prywatności.