window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster już istnieje') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() Moc obiektów JavaScript - The Codest
The Codest
  • O nas
  • Nasze Usługi
    • Software Development
      • Frontend Development
      • Backend Development
    • Zespoły IT
      • Programiści frontendowi
      • Backend Dev
      • Inżynierowie danych
      • Inżynierowie rozwiązań chmurowych
      • Inżynierowie QA
      • Inne
    • Konsultacje IT
      • Audyt i doradztwo
  • Branże
    • Fintech i bankowość
    • E-commerce
    • Adtech
    • Healthtech
    • Produkcja
    • Logistyka
    • Motoryzacja
    • IOT
  • Wartość dla
    • CEO
    • CTO
    • Delivery Managera
  • Nasz zespół
  • Case Studies
  • Nasze Know How
    • Blog
    • Meetups
    • Webinary
    • Raporty
Kariera Skontaktuj się z nami
  • O nas
  • Nasze Usługi
    • Software Development
      • Frontend Development
      • Backend Development
    • Zespoły IT
      • Programiści frontendowi
      • Backend Dev
      • Inżynierowie danych
      • Inżynierowie rozwiązań chmurowych
      • Inżynierowie QA
      • Inne
    • Konsultacje IT
      • Audyt i doradztwo
  • Wartość dla
    • CEO
    • CTO
    • Delivery Managera
  • Nasz zespół
  • Case Studies
  • Nasze Know How
    • Blog
    • Meetups
    • Webinary
    • Raporty
Kariera Skontaktuj się z nami
Strzałka w tył WSTECZ
2020-10-13
Software Development

Moc obiektów JavaScript

The Codest

Bartosz Słysz

Software Engineer

Ostatnie kilka lat pokazało nam, że tworzenie stron internetowych się zmienia. Ponieważ do przeglądarek dodawano wiele funkcji i interfejsów API, musieliśmy używać ich we właściwy sposób. Językiem, któremu zawdzięczamy ten zaszczyt był JavaScript.

Początkowo deweloperzy nie byli przekonani do tego, jak został on zaprojektowany i mieli w większości negatywne wrażenia podczas korzystania z tego skryptu. Z czasem okazało się, że język ten ma ogromny potencjał, a kolejne standardy ECMAScript sprawiają, że niektóre mechaniki stają się bardziej ludzkie i, po prostu, lepsze. W tym artykule przyjrzymy się niektórym z nich.

Typy wartości w JS

Dobrze znana prawda o JavaScript jest to, że wszystko tutaj jest obiektem. Naprawdę wszystko: tablice, funkcje, ciągi znaków, liczby, a nawet wartości logiczne. Wszystkie typy wartości są reprezentowane przez obiekty i mają swoje własne metody i pola. Możemy jednak podzielić je na dwie kategorie: prymitywy i struktury. Wartości z pierwszej kategorii są niezmienne, co oznacza, że możemy ponownie przypisać zmiennej nową wartość, ale nie możemy modyfikować istniejącej wartości. Druga reprezentuje wartości, które mogą być zmieniane, więc powinny być interpretowane jako kolekcje właściwości, które możemy zastąpić lub po prostu wywołać metody, które są do tego przeznaczone. 

Zakres zadeklarowanych zmiennych

Zanim przejdziemy głębiej, wyjaśnijmy, co oznacza zakres. Można powiedzieć, że zakres jest jedynym obszarem, w którym możemy używać zadeklarowanych zmiennych. Przed standardem ES6 mogliśmy deklarować zmienne za pomocą instrukcji var i nadawać im zakres globalny lub lokalny. Pierwszy z nich to sfera, która pozwala nam na dostęp do niektórych zmiennych w dowolnym miejscu aplikacji, drugi jest po prostu dedykowany konkretnemu obszarowi - głównie funkcji.

Od czasu standardu ES2015, JavaScript ma trzy sposoby deklarowania zmiennych, które różnią się słowem kluczowym. Pierwszy z nich został opisany wcześniej: zmienne zadeklarowane za pomocą słowa kluczowego var są przypisane do bieżącego ciała funkcji. Standard ES6 pozwolił nam zadeklarować zmienne na bardziej ludzkie sposoby - w przeciwieństwie do instrukcji var, zmienne zadeklarowane za pomocą instrukcji const i let są ograniczone tylko do bloku. Jednak JS traktuje instrukcję const dość nietypowo w porównaniu z innymi instrukcjami. języki programowania - zamiast trwałej wartości, przechowuje trwałą referencję do wartości. Krótko mówiąc, możemy modyfikować właściwości obiektu zadeklarowanego za pomocą instrukcji const, ale nie możemy nadpisać referencji do tej zmiennej. Niektórzy twierdzą, że alternatywa var w ES6 jest w rzeczywistości instrukcją let. Nie, nie jest, a instrukcja var nie jest i prawdopodobnie nigdy nie zostanie wycofana. Dobrą praktyką jest unikanie używania instrukcji var, ponieważ w większości przypadków przysparzają nam one więcej kłopotów. Z kolei należy nadużywać instrukcji const, dopóki nie musimy zmodyfikować jej referencji - wtedy powinniśmy użyć let. 

Przykład nieoczekiwanego zachowania zakresu

Zacznijmy od następujących rzeczy kod: 

(() => {
 for (var i = 0; i  {
      console.log(`Wartość "i": ${i}`);
    }, 1000);
  }
})();

Kiedy na to spojrzymy, wygląda na to, że pętla for iteruje wartość i, a po jednej sekundzie rejestruje wartości iteratora: 1, 2, 3, 4, 5. Ale tak nie jest. Jak wspomnieliśmy powyżej, instrukcja var polega na przechowywaniu wartości zmiennej przez całe ciało funkcji; oznacza to, że w drugiej, trzeciej i tak dalej iteracji wartość zmiennej i zostanie zastąpiona kolejną wartością. W końcu pętla kończy się, a tyknięcia limitu czasu pokazują nam następującą rzecz: 5, 5, 5, 5, 5. Najlepszym sposobem na zachowanie aktualnej wartości iteratora jest użycie instrukcji let:

(() => {
 for (let i = 0; i  {
      console.log(`Wartość "i": ${i}`);
    }, 1000);
  }
})();

W powyższym przykładzie utrzymujemy zakres wartości i w bieżącym bloku iteracji, jest to jedyny obszar, w którym możemy użyć tej zmiennej i nic nie może jej nadpisać spoza tego obszaru. Wynik w tym przypadku jest zgodny z oczekiwaniami: 1 2 3 4 5. Przyjrzyjmy się, jak poradzić sobie z tą sytuacją za pomocą instrukcji var: 

(() => {
 for (var i = 0; i  {
      setTimeout(() => {
        console.log(`Wartość "j": ${j}`);
      }, 1000);
    })(i);
  }
})();

Ponieważ instrukcja var dotyczy przechowywania wartości wewnątrz bloku funkcji, musimy wywołać zdefiniowaną funkcję, która przyjmuje argument - wartość bieżącego stanu iteratora - a następnie po prostu coś zrobić. Nic poza zadeklarowaną funkcją nie zastąpi wartości j. 

Przykłady błędnych oczekiwań dotyczących wartości obiektów

Najczęściej popełnianym przestępstwem, które zauważyłem, jest ignorowanie mocy struktur i zmienianie ich właściwości, które są również modyfikowane w innych fragmentach kodu. Wystarczy spojrzeć: 

const DEFAULT_VALUE = {
  favoriteBand: 'The Weeknd'
};
const currentValue = DEFAULT_VALUE;
const bandInput = document.querySelector('#favorite-band');
const restoreDefaultButton = document.querySelector('#restore-button');
bandInput.addEventListener('input', () => {
  currentValue.favoriteBand = bandInput.value;
}, false);
restoreDefaultButton.addEventListener('click', () => {
  currentValue = DEFAULT_VALUE;
}, false);

Od początku: załóżmy, że mamy model z domyślnymi właściwościami, przechowywany jako obiekt. Chcemy mieć przycisk, który przywraca wartości wejściowe do wartości domyślnych. Po wypełnieniu danych wejściowych pewnymi wartościami, aktualizujemy model. Po chwili uznajemy, że domyślny wybór był po prostu lepszy, więc chcemy go przywrócić. Klikamy przycisk... i nic się nie dzieje. Dlaczego? Z powodu ignorowania mocy wartości referencyjnych. 

Ta część: const currentValue = DEFAULTVALUE mówi JS, co następuje: weź odniesienie do DEFAULTVALUE i przypisać do niej zmienną currentValue. Rzeczywista wartość jest przechowywana w pamięci tylko raz i obie zmienne na nią wskazują. Modyfikowanie niektórych właściwości w jednym miejscu oznacza modyfikowanie ich w innym. Mamy kilka sposobów na uniknięcie takich sytuacji. Jednym z nich jest operator rozrzutu. Poprawmy nasz kod:

const DEFAULT_VALUE = {
  favoriteBand: 'The Weeknd'
};
const currentValue = { ...DEFAULT_VALUE };
const bandInput = document.querySelector('#favorite-band');
const restoreDefaultButton = document.querySelector('#restore-button');
bandInput.addEventListener('input', () => {
  currentValue.favoriteBand = bandInput.value;
}, false);
restoreDefaultButton.addEventListener('click', () => {
  currentValue = { ...DEFAULT_VALUE };
}, false);

W tym przypadku operator spread działa w następujący sposób: pobiera wszystkie właściwości z obiektu i tworzy nowy obiekt wypełniony nimi. Dzięki temu wartości w currentValue i DEFAULT_VALUE nie wskazują już na to samo miejsce w pamięci i wszelkie zmiany zastosowane do jednej z nich nie będą miały wpływu na pozostałe. 

Ok, więc pytanie brzmi: czy chodzi tylko o użycie magicznego operatora spreadu? W tym przypadku - tak, ale nasze modele mogą wymagać większej złożoności niż ten przykład. W przypadku, gdy używamy zagnieżdżonych obiektów, tablic lub innych struktur, operator rozprzestrzeniania wartości odniesienia najwyższego poziomu wpłynie tylko na najwyższy poziom, a właściwości, do których się odwołujemy, nadal będą współdzielić to samo miejsce w pamięci. Istnieje wiele rozwiązań tego problemu, wszystko zależy od potrzeb użytkownika. Możemy klonować obiekty na każdym poziomie głębokości lub, w bardziej złożonych operacjach, korzystać z narzędzi takich jak immer, które pozwalają nam pisać niezmienny kod niemal bezboleśnie.

Wymieszaj wszystko razem

Czy połączenie wiedzy o zakresach i typach wartości jest użyteczne? Oczywiście, że tak! Zbudujmy coś, co wykorzystuje oba te typy: 

 const useValue = (defaultValue) => {
 const value = [...defaultValue];
 const setValue = (newValue) => {
    value.length = 0; // trudny sposób na wyczyszczenie tablicy
    newValue.forEach((item, index) => {
      value[index] = item;
    });
 // zrób kilka innych rzeczy
  };

 return [value, setValue];
};
const [animals, setAnimals] = useValue(['cat', 'dog']);
console.log(animals); // ['kot', 'pies']
setAnimals(['koń', 'krowa']);
console.log(animals); // ['koń', 'krowa']);

Wyjaśnijmy, jak działa ten kod linijka po linijce. Cóż, funkcja useValue tworzy tablicę na podstawie argumentu defaultValue; tworzy zmienną i inną funkcję, jej modyfikator. Ten modyfikator przyjmuje nową wartość, która jest w podstępny sposób stosowana do istniejącej. Na końcu funkcji zwracamy wartość i jej modyfikator jako wartości tablicowe. Następnie używamy utworzonej funkcji - deklarujemy animals i setAnimals jako zwracane wartości. Używamy ich modyfikatora, aby sprawdzić, czy funkcja wpływa na zmienną animal - tak, to działa! 

Ale zaraz, co dokładnie jest takiego wymyślnego w tym kodzie? Referencja przechowuje wszystkie nowe wartości i można wprowadzić własną logikę do tego modyfikatora, np. niektóre interfejsy API lub część ekosystemu który zasila przepływ danych bez żadnego wysiłku. Ten trudny wzorzec jest często używany w bardziej nowoczesnych bibliotekach JS, gdzie funkcjonalny paradygmat programowania pozwala nam utrzymać kod mniej skomplikowany i łatwiejszy do odczytania przez innych programistów. 

Podsumowanie

Zrozumienie tego, jak mechanika języka działa pod maską, pozwala nam pisać bardziej świadomy i lekki kod. Nawet jeśli JS nie jest językiem niskopoziomowym i zmusza nas do posiadania pewnej wiedzy na temat przydzielania i przechowywania pamięci, nadal musimy uważać na nieoczekiwane zachowania podczas modyfikowania obiektów. Z drugiej strony, nadużywanie klonów wartości nie zawsze jest właściwą drogą, a nieprawidłowe użycie ma więcej wad niż zalet. Właściwym sposobem planowania przepływu danych jest zastanowienie się, czego potrzebujemy i jakie możliwe przeszkody możemy napotkać podczas wdrażania logiki aplikacji.

Czytaj więcej:

  • Jak ulepszyć aplikacje Vue.js? Kilka praktycznych wskazówek
  • Funkcje Vuex, które powinieneś znać, jeśli naprawdę zależy Ci na swoim sklepie
  • Jak napisać dobry i jakościowy kod?

Powiązane artykuły

Software Development

Tworzenie przyszłościowych aplikacji internetowych: spostrzeżenia zespołu ekspertów The Codest

Odkryj, w jaki sposób The Codest wyróżnia się w tworzeniu skalowalnych, interaktywnych aplikacji internetowych przy użyciu najnowocześniejszych technologii, zapewniając płynne doświadczenia użytkowników na wszystkich platformach. Dowiedz się, w jaki sposób nasza wiedza napędza transformację cyfrową i biznes...

THEECODEST
Software Development

10 najlepszych firm tworzących oprogramowanie na Łotwie

Dowiedz się więcej o najlepszych łotewskich firmach programistycznych i ich innowacyjnych rozwiązaniach w naszym najnowszym artykule. Odkryj, w jaki sposób ci liderzy technologiczni mogą pomóc w rozwoju Twojej firmy.

thecodest
Rozwiązania dla przedsiębiorstw i scaleupów

Podstawy tworzenia oprogramowania Java: Przewodnik po skutecznym outsourcingu

Zapoznaj się z tym niezbędnym przewodnikiem na temat skutecznego tworzenia oprogramowania Java outsourcing, aby zwiększyć wydajność, uzyskać dostęp do wiedzy specjalistycznej i osiągnąć sukces projektu z The Codest.

thecodest
Software Development

Kompletny przewodnik po outsourcingu w Polsce

Wzrost liczby outsourcing w Polsce jest napędzany przez postęp gospodarczy, edukacyjny i technologiczny, sprzyjający rozwojowi IT i przyjazny klimat dla biznesu.

TheCodest
Rozwiązania dla przedsiębiorstw i scaleupów

Kompletny przewodnik po narzędziach i technikach audytu IT

Audyty IT zapewniają bezpieczne, wydajne i zgodne z przepisami systemy. Dowiedz się więcej o ich znaczeniu, czytając cały artykuł.

The Codest
Jakub Jakubowicz CTO & Współzałożyciel

Subskrybuj naszą bazę wiedzy i bądź na bieżąco!

    O nas

    The Codest - Międzynarodowa firma programistyczna z centrami technologicznymi w Polsce.

    Wielka Brytania - siedziba główna

    • Office 303B, 182-184 High Street North E6 2JA
      Londyn, Anglia

    Polska - lokalne centra technologiczne

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Kraków
    • Brain Embassy, Konstruktorska
      11, 02-673 Warszawa, Polska

      The Codest

    • Strona główna
    • O nas
    • Nasze Usługi
    • Case Studies
    • Nasze Know How
    • Kariera
    • Słownik

      Nasze Usługi

    • Konsultacje IT
    • Software Development
    • Backend Development
    • Frontend Development
    • Zespoły IT
    • Backend Dev
    • Inżynierowie rozwiązań chmurowych
    • Inżynierowie danych
    • Inne
    • Inżynierowie QA

      Raporty

    • Fakty i mity na temat współpracy z zewnętrznym partnerem programistycznym
    • Z USA do Europy: Dlaczego amerykańskie startupy decydują się na relokację do Europy?
    • Porównanie centrów rozwoju Tech Offshore: Tech Offshore Europa (Polska), ASEAN (Filipiny), Eurazja (Turcja)
    • Jakie są największe wyzwania CTO i CIO?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Warunki korzystania z witryny

    Copyright © 2025 by The Codest. Wszelkie prawa zastrzeżone.

    pl_PLPolish
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench arArabic it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek pl_PLPolish