Skip to content

5. Obiekty literałowe

W tym kontekście terminem „obiekty literałowe” określamy obiekty zdefiniowane dosłownie w kodzie. W języku JavaScript istnieje pojęcie klasy oraz obiektu będącego instancją klasy. Nie jest to zatem ten rodzaj obiektu, o którym obecnie mówimy.

Image

5.1. skrypt [obj-01]

Przedstawiamy tutaj podstawowe właściwości obiektów literałowych. Najważniejszą z nich jest to, że obiektem manipuluje się za pomocą wskaźnika.


'use strict';
// pusty obiekt
const obj1={};
// można dynamicznie tworzyć właściwości obiektu
obj1.prop1="abcd";
console.log('obj1=',obj1);
// inna właściwość
obj1.prop2=[1,2,3];
console.log("obj1=",obj1);
// inna właściwość zapisana w inny sposób
obj1['prop3']=true;
console.log("obj1=",obj1);
// obj1 jest odwołaniem do obiektu (wskaźnikiem), a nie samym obiektem
const obj2=obj1;
// obj2 i obj1 wskazują na ten sam obiekt
obj2.prop1="xyzt";
console.log("obj1=",obj1);
console.log("obj2=",obj2);
// właściwości mogą być zmiennymi
const var1='prop1';
console.log('prop1=',obj1[var1]);

Wykonanie


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\objets\obj-01.js"
obj1=[object Object]
obj1= { prop1: 'abcd', prop2: [ 1, 2, 3 ] }
obj1= { prop1: 'abcd', prop2: [ 1, 2, 3 ], prop3: true }
obj1= { prop1: 'xyzt', prop2: [ 1, 2, 3 ], prop3: true }
obj2= { prop1: 'xyzt', prop2: [ 1, 2, 3 ], prop3: true }
prop1= xyzt

Komentarze

  • wiersz 3 kodu: obiekt jest obsługiwany za pomocą wskaźnika. Zatem [obj1] jest wskaźnikiem. Modyfikacja obiektu, na który wskazuje wskaźnik, nie powoduje zmiany samego wskaźnika [obj1]. Dlatego, podobnie jak w przypadku tablic, referencja do obiektu jest deklarowana za pomocą słowa kluczowego [const];
  • wiersz 6 kodu: podobnie jak w przypadku tablic, [console.log] potrafi wyświetlać obiekty;
  • wiersz 11 kodu: obj1.prop3 można zapisać jako obj1.[‘prop3’]. Ten ostatni zapis jest przydatny, gdy „prop3” jest w rzeczywistości zmienną (wiersze 20–21);
  • wiersze 13–18 kodu: pokazują, że instrukcja [obj2=obj1] stanowi kopiowanie przez odwołanie do obiektu, a nie samego obiektu;

5.2. skrypt [obj-02]

Skrypt ten pokazuje, że właściwości obiektu mogą przyjmować wartość obiektu. W ten sposób powstają obiekty wielopoziomowe. Wprowadzono również obiekt globalny [JSON], który umożliwia konwersję między obiektem a ciągiem znaków.


'use strict';
// obiekt wielopoziomowy
const personne = {
  prénom: "martin",
  âge: 12,
  père: {
    prénom: "paul",
    âge: 45
  },
  mère: {
    prénom: "micheline",
    âge: 42
  }
}
// dostęp do właściwości
console.log("prénom personne=", personne.prénom);
console.log("prénom mère=", personne.mère.prénom);
personne.mère.âge = 40;
console.log("âge mère=", personne.mère.âge);
// console.log potrafi wyświetlać obiekty
console.log("personne=", personne);
console.log("mère=", personne.mère);
// można również wyświetlić ciąg znaków jSON obiektu
let json = JSON.stringify(personne);
console.log("jSON=", json);
// można ponownie odczytać jSON
let personne2 = JSON.parse(json);
console.log("père=", personne2.père);

Komentarze

  • wiersz 24: przekształcenie obiektu JavaScript na ciąg znaków jSON;
  • wiersz 27: przekształcenie ciągu znaków jSON w obiekt JavaScript;

Wykonanie


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\objets\obj-02.js"
prénom personne= martin
prénom mère= micheline
âge mère= 40
personne= { 'prénom': 'martin',
'wiek': 12,
'ojciec': { 'imię': 'paul', 'wiek': 45 },
'matka': { 'imię': 'micheline', 'wiek': 40 } }
mère= { 'prénom': 'micheline', 'âge': 40 }
jSON= {"prénom":"martin","âge":12,"père":{"prénom":"paul","âge":45},"mère":{"prénom":"micheline","âge":40}}
père= { 'prénom': 'paul', 'âge': 45 }

Komentarze

  • wiersz 10: w ciągu znaków jSON właściwości muszą być ujęte w cudzysłowy, podobnie jak wartości typu ciąg znaków;

5.3. skrypt [obj-03]

Ten skrypt wprowadza pojęcie metod getter i setter właściwości obiektu:


'use strict';
// metody getter i setter obiektu
const personne = {
  // getter
  get nom() {
    console.log("getter nom");
    return this._nom;
  },
  // setter
  set nom(unNom) {
    console.log("setter nom");
    this._nom = unNom;
  }
};
// setter
personne.nom = "Hercule";
// metoda pobierająca
console.log(personne.nom);
// sam obiekt
console.log("personne=", personne);
// nie uniemożliwia to bezpośredniego dostępu do właściwości [_nom]
personne._nom = "xyz";
console.log("personne=", personne);

Komentarze

  • wiersze 5–7: definicja funkcji [getter], która zazwyczaj zwraca wartość właściwości obiektu, ale w rzeczywistości może zwracać dowolną wartość. Słowo kluczowe [function] zostało zastąpione słowem kluczowym [get];
  • wiersz 7: getter zwraca właściwość [_nom]. Widać, że nie trzeba jej deklarować;
  • wiersze 10–13: definicja funkcji [setter], która zazwyczaj przypisuje otrzymaną wartość do właściwości obiektu, ale w rzeczywistości może wykonywać dowolną operację. Słowo kluczowe [function] zostaje zastąpione słowem kluczowym [set]. Funkcja [setter] może służyć do sprawdzania poprawności wartości przekazanej jako parametr do funkcji [setter];
  • wiersz 16: funkcja [set nom] zostanie wywołana niejawnie;
  • wiersz 18: funkcja [get nom] zostanie wywołana niejawnie;
  • wiersz 22: pokazuje, że korzystanie z metod getter/setter zależy od decyzji programisty. Jeśli programista zna nazwę właściwości obsługiwanej przez te metody, może uzyskać do niej bezpośredni dostęp;

Wykonanie


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\objets\obj-03.js"
setter nom
getter nom
Hercule
personne= { nom: [Getter/Setter], _nom: 'Hercule' }
personne= { nom: [Getter/Setter], _nom: 'xyz' }

Warto zwrócić uwagę na linie 5–6, gdzie wskaźnik [console.log] wyświetla również właściwości, które są funkcjami.

5.4. skrypt [obj-04]

Ten skrypt pokazuje trzy sposoby zapisywania nazw właściwości obiektu oraz dwa sposoby uzyskiwania do nich dostępu.


'use strict';
// nazwy właściwości obiektu  mogą być literałami [nom], otoczone apostrofami ['nom']
// lub cudzysłowami ["nom"]

// literały
const obj1 = {
  nom: "martin",
  prénom: "jean"
};
console.log("prénom=", obj1.prénom);

// otoczone apostrofami
const obj2 = {
  'nazwisko': „martin”,
  'imię': „jean”
};
console.log("nom=", obj2.nom);

// w cudzysłowach
const obj3 = {
  "nom": "martin",
  "prénom": "jean"
};

// dwie możliwe składnie dostępu do właściwości [nom]
console.log("nom=", obj3.nom);
console.log("nom=", obj3['nom']);

Wykonanie


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\objets\obj-04.js"
prénom= jean
nom= martin
nom= martin
nom= martin

5.5. skrypt [obj-05]

Skrypt pokazuje, że właściwości obiektu literałowego mogą być funkcjami. Jesteśmy wtedy bardzo blisko obiektu będącego instancją klasy, w którym występują właściwości i metody.


'use strict';

// obiekt może posiadać właściwości typu [function]
const personne = {
  // właściwości
  prénom: "martin",
  âge: 12,
  père: {
    prénom: "paul",
    âge: 45
  },
  mère: {
    prénom: "micheline",
    âge: 42
  },
  // metoda
  toString: function () {
    return JSON.stringify(this);
  }
}

// zastosowanie
console.log("personne=", personne);
console.log("personne.toString=", personne.toString());
  • wiersze 17–19: metoda wewnętrzna obiektu. W tej metodzie uzyskuje się dostęp do właściwości obiektu za pomocą słowa kluczowego [this] (wiersz 18). [this] oznacza sam obiekt, a [this.prénom] – jego właściwość [prénom];

Wykonanie


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\objets\obj-05.js"
personne= { 'prénom': 'martin',
'wiek': 12,
'ojciec': { 'imię': 'paul', 'wiek': 45 },
'matka': { 'imię': 'micheline', 'wiek': 42 },
toString: [Function: toString] }
personne.toString= {"prénom":"martin","âge":12,"père":{"prénom":"paul","âge":45},"mère":{"prénom":"micheline","âge":42}}

5.6. skrypt [obj-06]

Ten skrypt pokazuje, jak uzyskać dostęp do właściwości obiektu, gdy nie znamy z góry ich nazw.


'use strict';

// obiekt może posiadać właściwości typu [function]
let personne = {
  // właściwości
  prénom: "martin",
  âge: 12,
  père: {
    prénom: "paul",
    âge: 45
  },
  mère: {
    prénom: "micheline",
    âge: 42
  },
  // metoda
  toString: function () {
    return JSON.stringify(this);
  }
}

// zastosowanie
console.log(personne);
// właściwości
console.log("-----------------------");
for (const key in personne) {
  if (personne.hasOwnProperty(key)) {
    const element = personne[key];
    console.log(key, "=", element);
  }
}
// aby uniknąć ostrzeżenia eslint (1)
console.log("-----------------------");
for (const key in personne) {
  if (Object.prototype.hasOwnProperty.call(personne, key)) {
    const element = personne[key];
    console.log(key, "=", element);
  }
}
// aby uniknąć ostrzeżenia eslint (2)
console.log("-----------------------");
for (const key in personne) {
  // eslint-disable-next-line no-prototype-builtins
  if (personne.hasOwnProperty(key)) {
    const element = personne[key];
    console.log(key, "=", element);
  }
}

Komentarze

  • wiersze 26–31: kod umożliwiający uzyskanie listy właściwości obiektu, z wyłączeniem metod. Kod ten jest przedmiotem ostrzeżenia ESLint:

Image

  • wiersze 32–39: kod pozwalający uniknąć ostrzeżenia o błędzie ESLint. Wykorzystuje się prototyp klasy [Object];
  • wiersze 41–47: albo po prostu wyłączamy ostrzeżenie (wiersz 43);

5.7. skrypt [obj-07]

Skrypt [obj-07] pokazuje możliwość dekonstrukcji obiektu:


'„use strict”;
// dekonstrukcja

// literały
const obj1 = {
  nom: "martin",
  prénom: "jean"
};

// dekonstrukcja obj1 w zmiennych [n,p]
const { nom: n, prénom: p } = obj1;
console.log("n=", n, "p=", p);

// dekonstrukcja obiektu obj1 do zmiennych [n2,p2]
function f({ nom: n2, prénom: p2 }) {
  console.log("f-n2=", n2, "f-p2=", p2);
}
f(obj1);

// dekonstrukcja obiektu obj1 na zmienne [nom,prénom]
function g({ nom: nom, prénom: prénom }) {
  console.log("g-nom=", nom, "g-prénom=", prénom);
}
g(obj1);

// dekonstrukcja obiektu obj1 na zmienne [nom,prénom]
// z notacją skróconą równoważną h({nazwisko:nazwisko,imię:imię})
function h({ nom, prénom }) {
  console.log("h-nom=", nom, "h-prénom=", prénom);
}
h(obj1);

Komentarze

  • wiersz 11: to właśnie nawiasy klamrowe {} umożliwiają dekonstrukcję. Składnia

const { nom: n, prénom: p } = obj1

tworzy dwie zmienne [n] i [p] i jest równoważna następującemu zapisowi:


const n = obj1.nom
const p = obj1.prénom

Deklaracja mogłaby wyglądać następująco:


const { nom => n, prénom => p } = obj1

należy pamiętać, że wartości atrybutów [nom, prénom] trafiają do zmiennych [n, p];

  • operacja dekonstrukcji powtarza się w wierszach 15, 21 i 28. Za każdym razem obecność nawiasów klamrowych {} wskazuje, że nastąpi dekonstrukcja obiektu do zmiennych;
  • wiersz 28 może budzić pewne wątpliwości. Jest to skrót dla zapisu:

function h({ nom : nom, prénom : prénom })

Wyniki wykonania są następujące:

1
2
3
4
n= martin p= jean
f-n2= martin f-p2= jean
g-nom= martin g-prénom= jean
h-nom= martin h-prénom= jean

5.8. skrypt [obj-08]

Skrypt [obj-08] pokazuje, jak uzyskać kopię obiektu:


'use strict'

// klonowanie obiektów
const obj1 = {
  nom: "martin",
  prénom: "jean"
};

// klon (kopia) obiektu obj1 przy użyciu operatora rozprzestrzeniania
const obj2 = { ...obj1 }

// sprawdzanie
// obj2 wskazuje na kopię obj1
console.log("obj2===obj1 :", obj1 === obj2)
console.log("obj2=", obj2)
  • wiersz 10: operacja kopiowania obiektu [obj1]. Operator ... nazywany jest operatorem rozprzestrzeniania;

Wyniki wykonania są następujące:

obj2===obj1 : false
obj2= { nom: 'martin', 'prénom': 'jean' }
  • wiersz 1: pokazuje, że referencje [obj1] i [obj2] nie wskazują na ten sam obiekt;
  • wiersz 2: pokazuje, że obiekt, na który wskazuje [obj2], jest kopią obiektu, na który wskazuje [obj1];

5.9. Conclusion

Skrypty z tej sekcji pokazały, że obiekt literałowy w JavaScript jest zbliżony do obiektu instancji klasy w językach obiektowych. Można w nim definiować właściwości, metody oraz gettery i settery. Jest to obiekt dynamiczny, którego właściwości można definiować w trakcie wykonywania. Zachowuje się on wówczas jak słownik, którego elementy mogą być dowolnego typu, w szczególności typu [fonction].