Objekty

Jak víme z kapitoly Datové typy, v JavaScriptu existuje osm datových typů. Sedm z nich se nazývá „primitivní“, protože jejich hodnoty obsahují pouze jednu věc (ať už je to řetězec nebo číslo nebo cokoli jiného).

Naproti tomu objekty slouží k ukládání klíčovaných kolekcí různých dat a složitějších entit. V JavaScriptu objekty pronikají téměř do všech aspektů jazyka. Musíme jim tedy nejprve porozumět, než se pustíme do hloubky kdekoli jinde.

Objekt lze vytvořit pomocí číselných závorek {…} s volitelným seznamem vlastností . Vlastnost je pár „klíč:hodnota“, kde key je řetězec (nazývaný také „název vlastnosti“) a value může být cokoliv.

Objekt si můžeme představit jako skříň s podepsanými soubory. Každý kus dat je uložen ve svém souboru pomocí klíče. Je snadné najít soubor podle jeho názvu nebo přidat/odebrat soubor.

Prázdný objekt („prázdná skříň“) lze vytvořit pomocí jedné ze dvou syntaxí:

let user = new Object(); // "object constructor" syntax
let user = {}; // "object literal" syntax

Obvykle je číslo v závorkách {...} Jsou používány. Tato deklarace se nazývá objektový literál .

Literály a vlastnosti

Některé vlastnosti můžeme okamžitě vložit do {...} jako páry „klíč:hodnota“:

let user = { // an object
 name: "John", // by key "name" store value "John"
 age: 30 // by key "age" store value 30
};

Vlastnost má před dvojtečkou ":" klíč (také známý jako „název“ nebo „identifikátor“) a hodnotu napravo od něj.

V user objekt, existují dvě vlastnosti:

  1. První vlastnost má název "name" a hodnotu "John" .
  2. Druhý má název "age" a hodnotu 30 .

Výsledný user objekt si lze představit jako skříň se dvěma podepsanými soubory označenými „jméno“ a „věk“.

Můžeme z něj kdykoli přidávat, odebírat a číst soubory.

Hodnoty vlastností jsou přístupné pomocí tečkové notace:

// get property values of the object:
alert( user.name ); // John
alert( user.age ); // 30

Hodnota může být libovolného typu. Přidejme jeden booleovský:

user.isAdmin = true;

K odstranění vlastnosti můžeme použít delete operátor:

delete user.age;

Můžeme také použít víceslovné názvy vlastností, ale pak musí být uvedeny v uvozovkách:

let user = {
 name: "John",
 age: 30,
 "likes birds": true // multiword property name must be quoted
};

Poslední vlastnost v seznamu může končit čárkou:

let user = {
 name: "John",
 age: 30,
}

To se nazývá „závěsná“ nebo „závěsná“ čárka. Usnadňuje přidávání/odebírání/přesouvání vlastností, protože všechny čáry se stanou stejnými.

Hranaté závorky

U víceslovných vlastností nefunguje bodový přístup:

// this would give a syntax error
user.likes birds = true

JavaScript tomu nerozumí. Myslí si, že adresujeme user.likes a poté zobrazí chybu syntaxe, když narazí na neočekávaný birds .

Tečka vyžaduje, aby klíč byl platným identifikátorem proměnné. To znamená:neobsahuje mezery, nezačíná číslicí a neobsahuje speciální znaky ($ a _ jsou povoleny).

Existuje alternativní „závorka“, která funguje s libovolným řetězcem:

let user = {};

// set
user["likes birds"] = true;

// get
alert(user["likes birds"]); // true

// delete
delete user["likes birds"];

Nyní je vše v pořádku. Vezměte prosím na vědomí, že řetězec v závorkách je správně uvozován (postačí jakýkoli typ uvozovek).

Hranaté závorky také poskytují způsob, jak získat název vlastnosti jako výsledek jakéhokoli výrazu – na rozdíl od doslovného řetězce – například z proměnné takto:

let key = "likes birds";

// same as user["likes birds"] = true;
user[key] = true;

Zde proměnná key lze vypočítat za běhu nebo záviset na vstupu uživatele. A pak to použijeme pro přístup k nemovitosti. To nám dává velkou flexibilitu.

Například:

let user = {
 name: "John",
 age: 30
};

let key = prompt("What do you want to know about the user?", "name");

// access by variable
alert( user[key] ); // John (if enter "name")

Tečkovou notaci nelze použít podobným způsobem:

let user = {
 name: "John",
 age: 30
};

let key = "name";
alert( user.key ) // undefined

Vypočítané vlastnosti

Při vytváření objektu můžeme v objektovém literálu použít hranaté závorky. Říká se tomu vypočítané vlastnosti .

Například:

let fruit = prompt("Which fruit to buy?", "apple");

let bag = {
 [fruit]: 5, // the name of the property is taken from the variable fruit
};

alert( bag.apple ); // 5 if fruit="apple"

Význam vypočítané vlastnosti je jednoduchý:[fruit] znamená, že název vlastnosti by měl být převzat z fruit .

Pokud tedy návštěvník zadá "apple" , bag bude {apple: 5} .

V podstatě to funguje stejně jako:

let fruit = prompt("Which fruit to buy?", "apple");
let bag = {};

// take property name from the fruit variable
bag[fruit] = 5;

…Ale vypadá to lépe.

Můžeme použít složitější výrazy uvnitř hranatých závorek:

let fruit = 'apple';
let bag = {
 [fruit + 'Computers']: 5 // bag.appleComputers = 5
};

Hranaté závorky jsou mnohem výkonnější než tečková notace. Umožňují libovolné názvy vlastností a proměnné. Ale jsou také obtížnější na psaní.

Takže většinou, když jsou názvy vlastností známé a jednoduché, používá se tečka. A pokud potřebujeme něco složitějšího, pak přejdeme na hranaté závorky.

Zkratka hodnoty vlastnosti

Ve skutečném kódu často používáme existující proměnné jako hodnoty pro názvy vlastností.

Například:

function makeUser(name, age) {
 return {
 name: name,
 age: age,
 // ...other properties
 };
}

let user = makeUser("John", 30);
alert(user.name); // John

Ve výše uvedeném příkladu mají vlastnosti stejné názvy jako proměnné. Případ použití vytvoření vlastnosti z proměnné je tak běžný, že existuje speciální zkrácený popis hodnoty vlastnosti aby to bylo kratší.

Místo name:name stačí napsat name , takto:

function makeUser(name, age) {
 return {
 name, // same as name: name
 age, // same as age: age
 // ...
 };
}

Ve stejném objektu můžeme použít normální vlastnosti i zkratky:

let user = {
 name, // same as name:name
 age: 30
};

Omezení názvů vlastností

Jak již víme, proměnná nemůže mít název rovný jednomu z jazykově vyhrazených slov jako „pro“, „nechat“, „vrátit“ atd.

Ale pro vlastnost objektu žádné takové omezení neexistuje:

// these properties are all right
let obj = {
 for: 1,
 let: 2,
 return: 3
};

alert( obj.for + obj.let + obj.return ); // 6

Stručně řečeno, neexistují žádná omezení pro názvy vlastností. Mohou to být libovolné řetězce nebo symboly (speciální typ pro identifikátory, který bude popsán později).

Ostatní typy jsou automaticky převedeny na řetězce.

Například číslo 0 se stane řetězcem "0" při použití jako klíč vlastnosti:

let obj = {
 0: "test" // same as "0": "test"
};

// both alerts access the same property (the number 0 is converted to string "0")
alert( obj["0"] ); // test
alert( obj[0] ); // test (same property)

Existuje menší problém se speciální vlastností s názvem __proto__ . Nemůžeme ji nastavit na neobjektovou hodnotu:

let obj = {};
obj.__proto__ = 5; // assign a number
alert(obj.__proto__); // [object Object] - the value is an object, didn't work as intended

Jak vidíme z kódu, přiřazení k primitivnímu 5 je ignorováno.

Pokryjeme zvláštní povahu __proto__ v následujících kapitolách a navrhněte způsoby, jak takové chování napravit.

Test existence vlastnosti, operátor „in“

Pozoruhodnou vlastností objektů v JavaScriptu ve srovnání s mnoha jinými jazyky je to, že je možné přistupovat k jakékoli vlastnosti. Pokud vlastnost neexistuje, nedojde k žádné chybě!

Čtení neexistující vlastnosti pouze vrátí undefined . Můžeme tedy snadno otestovat, zda vlastnost existuje:

let user = {};

alert( user.noSuchProperty === undefined ); // true means "no such property"

Existuje také speciální operátor "in" za to.

Syntaxe je:

"key" in object

Například:

let user = { name: "John", age: 30 };

alert( "age" in user ); // true, user.age exists
alert( "blabla" in user ); // false, user.blabla doesn't exist

Upozorňujeme, že na levé straně in musí existovat název vlastnosti . To je obvykle řetězec v uvozovkách.

Pokud vynecháme uvozovky, znamená to, že proměnná by měla obsahovat skutečný název, který má být testován. Například:

let user = { age: 30 };

let key = "age";
alert( key in user ); // true, property "age" exists

Proč in existuje operátor? Nestačí porovnat s undefined ?

No, většinou srovnání s undefined funguje dobře. Ale existuje zvláštní případ, kdy selže, ale "in" funguje správně.

Je to tehdy, když vlastnost objektu existuje, ale ukládá undefined :

let obj = {
 test: undefined
};

alert( obj.test ); // it's undefined, so - no such property?

alert( "test" in obj ); // true, the property does exist!

Ve výše uvedeném kódu vlastnost obj.test technicky existuje. Takže in operátor funguje správně.

K takovým situacím dochází velmi zřídka, protože undefined by neměly být explicitně přiřazeny. Většinou používáme null pro „neznámé“ nebo „prázdné“ hodnoty. Takže in operátor je v kódu exotický host.

Smyčka „for..in“

Chcete-li projít všechny klíče objektu, existuje speciální forma smyčky:for..in . To je úplně něco jiného než for(;;) konstrukt, který jsme předtím studovali.

Syntaxe:

for (key in object) {
 // executes the body for each key among object properties
}

Vypišme například všechny vlastnosti user :

let user = {
 name: "John",
 age: 30,
 isAdmin: true
};

for (let key in user) {
 // keys
 alert( key ); // name, age, isAdmin
 // values for the keys
 alert( user[key] ); // John, 30, true
}

Všimněte si, že všechny konstrukce „for“ nám umožňují deklarovat smyčkovou proměnnou uvnitř smyčky, jako je let key zde.

Také bychom zde mohli použít jiný název proměnné místo key . Například "for (let prop in obj)" je také široce používán.

Seřazeno jako objekt

Jsou předměty objednány? Jinými slovy, pokud projdeme smyčkou přes objekt, získáme všechny vlastnosti ve stejném pořadí, v jakém byly přidány? Můžeme se na to spolehnout?

Krátká odpověď zní:„seřazeno zvláštním způsobem“:celočíselné vlastnosti jsou seřazeny, ostatní se objevují v pořadí vytvoření. Podrobnosti následují.

Jako příklad uvažujme objekt s telefonními kódy:

let codes = {
 "49": "Germany",
 "41": "Switzerland",
 "44": "Great Britain",
 // ..,
 "1": "USA"
};

for (let code in codes) {
 alert(code); // 1, 41, 44, 49
}

Objekt lze použít k navržení seznamu možností uživateli. Pokud vytváříme web hlavně pro německé publikum, pak pravděpodobně chceme 49 být první.

Ale pokud spustíme kód, uvidíme úplně jiný obrázek:

  • USA (1) jsou na prvním místě
  • pak Švýcarsko (41) a tak dále.

Telefonní kódy jsou seřazeny vzestupně, protože se jedná o celá čísla. Vidíme tedy 1, 41, 44, 49 .

Celočíselné vlastnosti? co to je

Výraz „vlastnost celého čísla“ zde znamená řetězec, který lze beze změny převést na celé číslo az něj.

Takže "49" je celočíselný název vlastnosti, protože když je transformován na celé číslo a zpět, je stále stejný. Ale "+49" a "1.2" nejsou:

// Number(...) explicitly converts to a number
// Math.trunc is a built-in function that removes the decimal part
alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property
alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property
alert( String(Math.trunc(Number("1.2"))) ); // "1", not same "1.2" ⇒ not integer property

…Na druhou stranu, pokud klíče nejsou celočíselné, jsou uvedeny v pořadí vytváření, například:

let user = {
 name: "John",
 surname: "Smith"
};
user.age = 25; // add one more

// non-integer properties are listed in the creation order
for (let prop in user) {
 alert( prop ); // name, surname, age
}

Abychom vyřešili problém s telefonními kódy, můžeme „podvádět“ tím, že kódy nebudou celočíselné. Přidání plus "+" podepsat před každým kódem stačí.

Takhle:

let codes = {
 "+49": "Germany",
 "+41": "Switzerland",
 "+44": "Great Britain",
 // ..,
 "+1": "USA"
};

for (let code in codes) {
 alert( +code ); // 49, 41, 44, 1
}

Nyní to funguje, jak bylo zamýšleno.

Shrnutí

Objekty jsou asociativní pole s několika speciálními vlastnostmi.

Ukládají vlastnosti (páry klíč–hodnota), kde:

  • Klíče vlastností musí být řetězce nebo symboly (obvykle řetězce).
  • Hodnoty mohou být libovolného typu.

Pro přístup k vlastnosti můžeme použít:

  • Tečkový zápis:obj.property .
  • Zápis v hranatých závorkách obj["property"] . Hranaté závorky umožňují převzít klíč z proměnné, jako je obj[varWithKey] .

Další operátoři:

  • Smazání vlastnosti:delete obj.prop .
  • Chcete-li zkontrolovat, zda vlastnost s daným klíčem existuje:"key" in obj .
  • Pro iteraci objektu:for (let key in obj) smyčka.

To, co jsme studovali v této kapitole, se nazývá „prostý objekt“ nebo jen Object .

V JavaScriptu je mnoho dalších druhů objektů:

  • Array ukládat objednané kolekce dat,
  • Date k uložení informací o datu a čase,
  • Error k uložení informací o chybě.
  • …A tak dále.

Mají své speciální vlastnosti, které budeme studovat později. Někdy lidé říkají něco jako „Typ pole“ nebo „Typ data“, ale formálně to nejsou vlastní typy, ale patří k jedinému datovému typu „objektu“. A rozšiřují ji různými způsoby.

Objekty v JavaScriptu jsou velmi výkonné. Zde jsme právě načrtli povrch tématu, které je opravdu velké. S objekty budeme úzce spolupracovat a v dalších částech výukového programu se o nich dozvíme více.


No