Az object adattípus
A JavaScript egyik beépített adattípusa az object
(objektum). Ennek segítségével komplex entitásokat tudunk létrehozni, amelyekbe property-érték párokat helyezhetünk.
Object létrehozása
JavaScriptben objektumokat kétféleképpen hozhatunk létre:
- a
new Object()
konstruktor használatával
- a kapcsos zárójel (
{}
) operátorok segítségével.
Példa: Üres object-ek létrehozása
| let empty1 = new Object();
let empty2 = {};
|
A továbbiakban a kapcsos zárójeles szintaxist fogjuk használni a jegyzetben. A kapcsos zárójel között, vesszővel elválasztva megadhatjuk az adott objektum property-érték párjait property: érték
formában.
Példa: Egy személy object létrehozása
| let person = {
name: "Bob",
age: 30,
occupation: "programmer",
married: false
};
|
Modern object létrehozási módszerek
Ha a változó neve megegyezik a property nevével, akkor nem kell megismételni, ez a shorthand property syntax.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | let name = "Bob";
let age = 30;
let occupation = "programmer";
// Old way
let person1 = {
name: name,
age: age,
occupation: occupation
};
// Modern shorthand way
let person2 = {
name,
age,
occupation
};
console.log(person2); // same result as person1
|
Object elemeinek elérése
Egy object adott property-jéhez tartozó értéke kétféleképpen is lekérdezhető:
- a
.
(pont) operátorral
- a
[]
(szögletes zárójel) operátorral.
Példa: A name
property-hez tartozó érték lekérése
| let person = { name: "Bob", age: 30, occupation: "programmer" };
console.log(person.name); // . operator
console.log(person["name"]); // [] operator
|
A lényegi különbség a két operátor működésében, hogy amennyiben változót adunk át nekik, akkor a .
operátor a változó nevét tekinti kulcsnak, míg a []
operátor a változó értékét fogja kulcsként venni.
Példa: A .
és []
operátorok közötti működésbeli különbség.
| let person = { name: "Bob", age: 30, occupation: "programmer" };
let something = "age";
console.log(person.something);
console.log(person[something]);
|
A példában az első esetben a .
operátor egy something
nevű property-t keresett az objektumon belül, amit nem talált meg, így undefined
értéket kaptunk. A második esetben a []
operátor, már a something
változóban szerepelő értéket, az age
property-t kereste, és mivel van ilyen property-nk az objektumunkban, ezért az ahhoz tartozó értéket kaptuk vissza.
Optional Chaining (?.)
Modern JavaScriptben biztonságosan érhetünk el mélyen egymásba ágyazott property-ket anélkül, hogy ellenőriznünk kellene minden szinten, hogy létezik-e:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | let user = {
name: "Alice",
address: {
city: "Budapest",
zipCode: 1011
}
};
let user2 = {
name: "Bob"
// no address property
};
// Old way - risky!
console.log(user.address.city); // "Budapest"
// console.log(user2.address.city); // ERROR! Cannot read property 'city' of undefined
// Old way - safe but verbose
console.log(user2.address ? user2.address.city : undefined); // undefined
// Modern way with optional chaining
console.log(user.address?.city); // "Budapest"
console.log(user2.address?.city); // undefined - no error!
console.log(user2.address?.city?.toString()); // undefined - safe chaining
|
Nullish Coalescing (??)
Az ??
operátor akkor ad vissza default értéket, ha a bal oldali érték null
vagy undefined
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | let user = {
name: "David",
age: 0,
city: null
};
// Old way with || (problematic with falsy values)
console.log(user.age || 18); // 18 - wrong! (0 is falsy)
console.log(user.city || "Unknown"); // "Unknown" - correct
// Modern way with ?? (only null/undefined)
console.log(user.age ?? 18); // 0 - correct! (0 is not null/undefined)
console.log(user.city ?? "Unknown"); // "Unknown" - correct
console.log(user.country ?? "Hungary"); // "Hungary" - correct
// Combining with optional chaining
console.log(user.address?.city ?? "No city"); // "No city"
|
Fontosabb object műveletek
Property előfordulásának ellenőrzése
Az in
operátorral tudjuk a megbízhatóan ellenőrizni, hogy egy property szerepel-e az objektumban:
1
2
3
4
5
6
7
8
9
10
11
12 | let person = { name: "Bob", age: 30, occupation: "programmer" };
if ("occupation" in person) {
console.log("Has occupation property!");
console.log("Value: " + person.occupation);
}
if ("salary" in person) {
console.log("Has salary property!");
} else {
console.log("No salary property found.");
}
|
Kimenet
Has occupation property!
Value: programmer
No salary property found.
Miért jobb az in
operátor mint az undefined
ellenőrzés?
| let person = { name: "Bob", age: 30, occupation: undefined };
// This won't work correctly
if (person.occupation !== undefined) {
console.log("Has occupation property!"); // doesn't print - wrong!
}
// This works correctly
if ("occupation" in person) {
console.log("Has occupation property!"); // prints - correct!
}
|
Kimenet
Has occupation property!
Érték módosítása
Az object egy adott property-jéhez tartozó értékét módosíthatjuk is. Hivatkozunk a módosítani kívánt elemre (a fentebb tárgyalt .
vagy []
operátorok valamelyikével), majd az =
operátorral beállítjuk az új értéket.
| let person = { name: "Bob", age: 30, occupation: "programmer" };
person.occupation = "astronaut"; // person["occupation"] = "astronaut" also works
console.log(person.name + " changed jobs, now an " + person.occupation + "!");
|
Kimenet
Bob changed jobs, now an astronaut!
Új property-érték pár beszúrása
Az objektumainkba bármikor beszúrhatunk új property-érték párokat. A beszúrás szintaxisa nagyon egyszerű: megadjuk az object beszúrni kívánt property-jének a nevét, majd =
operátorral értéket adunk neki.
| let person = { name: "Bob", age: 30, occupation: "programmer" };
person.favoriteColor = "transparent";
console.log(person);
|
Kimenet
{
name: 'Bob',
age: 30,
occupation: 'programmer',
favoriteColor: 'transparent'
}
Property-érték pár törlése
A delete
kulcsszóval lehetőségünk van egy adott property-t és a hozzá tartozó értéket törölni az object-ből.
| let person = { name: "Bob", age: 30, occupation: "programmer" };
delete person.occupation;
console.log(person);
|
Kimenet
{ name: 'Bob', age: 30 }
Object destructuring
Hasonlóan a tömbök destruktúrálásához, az objektumokból is kinyerhetünk property-ket változókba:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | let person = {
name: "Alice",
age: 25,
occupation: "designer",
city: "Budapest"
};
// Old way
let name = person.name;
let age = person.age;
// Modern destructuring way
let {name, age, occupation} = person;
console.log(name); // "Alice"
console.log(age); // 25
console.log(occupation); // "designer"
// Rename variables during destructuring
let {name: personName, age: personAge} = person;
console.log(personName); // "Alice"
console.log(personAge); // 25
// Default values
let {name, country = "Hungary"} = person;
console.log(country); // "Hungary" (not in original object)
// Rest operator for remaining properties
let {name, ...rest} = person;
console.log(name); // "Alice"
console.log(rest); // {age: 25, occupation: "designer", city: "Budapest"}
|
Object-ek bejárása
Az object-ek property-érték párjának bejárása legegyszerűbben egy for
-ciklussal tehető meg. Az alábbi módszerek mindegyike ezt valósítja meg (amelyik a legszimpatikusabb a számunkra, azt használjuk).
for-in szerkezet
| let person = { name: "Bob", age: 30, occupation: "programmer" };
for (let key in person) {
console.log(key + " value: " + person[key]);
}
|
for-of szerkezet Object.keys() használatával
| let person = { name: "Bob", age: 30, occupation: "programmer" };
for (let key of Object.keys(person)) {
console.log(key + " value: " + person[key]);
}
|
for-of szerkezet Object.entries() használatával (ajánlott)
| let person = { name: "Bob", age: 30, occupation: "programmer" };
for (let [key, value] of Object.entries(person)) {
console.log(key + " value: " + value);
}
|
Object.values() - csak az értékek
| let person = { name: "Bob", age: 30, occupation: "programmer" };
for (let value of Object.values(person)) {
console.log(value);
}
|
Kimenet
Bob
30
programmer
Spread operátor objektumokkal
A spread operátor (...
) használatával másolhatunk és egyesíthetünk objektumokat:
Objektum másolása (shallow copy)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | let original = {
name: "Alice",
age: 25,
city: "Budapest"
};
// Create a copy
let copy = {...original};
copy.age = 26;
console.log(original.age); // 25 - unchanged
console.log(copy.age); // 26 - changed
// Add new properties while copying
let extended = {
...original,
occupation: "designer",
country: "Hungary"
};
console.log(extended);
// {name: "Alice", age: 25, city: "Budapest", occupation: "designer", country: "Hungary"}
|
Objektumok egyesítése
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | let personal = {
name: "Bob",
age: 30
};
let work = {
occupation: "programmer",
company: "TechCorp"
};
let contact = {
email: "bob@example.com",
phone: "123-456-7890"
};
// Merge objects
let fullProfile = {...personal, ...work, ...contact};
console.log(fullProfile);
// Later properties override earlier ones
let obj1 = {a: 1, b: 2};
let obj2 = {b: 3, c: 4};
let merged = {...obj1, ...obj2};
console.log(merged); // {a: 1, b: 3, c: 4} - obj2.b overrides obj1.b
|
Override properties
1
2
3
4
5
6
7
8
9
10
11
12
13 | let user = {
name: "Charlie",
age: 28,
active: false
};
// Update specific properties
let updatedUser = {
...user,
active: true,
};
console.log(updatedUser);
|
Hasznos Object metódusok (érdekesség)
Object.keys(), Object.values(), Object.entries()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | let student = {
name: "Diana",
age: 22,
major: "Computer Science",
gpa: 3.8
};
// Get all property names
console.log(Object.keys(student));
// ["name", "age", "major", "gpa"]
// Get all values
console.log(Object.values(student));
// ["Diana", 22, "Computer Science", 3.8]
// Get all key-value pairs
console.log(Object.entries(student));
// [["name", "Diana"], ["age", 22], ["major", "Computer Science"], ["gpa", 3.8]]
// Count properties
console.log(Object.keys(student).length); // 4
|
Object.freeze() - objektum "befagyasztása"
Az Object.freeze()
segítségével létrehozhatunk változtathatatlan (immutable) objektumokat:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | let config = {
apiUrl: "https://api.example.com",
timeout: 5000,
retries: 3
};
Object.freeze(config);
// These modifications won't work (in strict mode: error)
config.timeout = 10000; // no effect
config.newProp = "test"; // no effect
delete config.retries; // no effect
console.log(config);
// {apiUrl: "https://api.example.com", timeout: 5000, retries: 3} - unchanged
|
Figyelem
Az Object.freeze()
csak "shallow" (sekély) befagyasztást végez. Ha az objektum beágyazott objektumokat tartalmaz, azok még módosíthatók lesznek!
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | let user = {
name: "Eve",
settings: {
theme: "dark",
language: "en"
}
};
Object.freeze(user);
user.name = "Eva"; // no effect
user.settings.theme = "light"; // THIS WORKS! - nested object not frozen
console.log(user.settings.theme); // "light"
|
Object.seal() - objektum "lezárása"
Az Object.seal()
megengedni a meglévő property-k módosítását, de nem engedélyezi új property-k hozzáadását vagy meglévők törlését:
1
2
3
4
5
6
7
8
9
10
11
12 | let user = {
name: "Frank",
age: 35
};
Object.seal(user);
user.age = 36; // OK - can modify existing properties
user.city = "Budapest"; // no effect - can't add new properties
delete user.name; // no effect - can't delete properties
console.log(user); // {name: "Frank", age: 36}
|
Objektumok összehasonlítása
Fontos: Az objektumokat JavaScriptben referencia szerint hasonlítja össze a nyelv, nem érték szerint!
| let obj1 = {name: "Alice", age: 25};
let obj2 = {name: "Alice", age: 25};
let obj3 = obj1; // same reference
console.log(obj1 === obj2); // false - different objects, even if content is same
console.log(obj1 === obj3); // true - same reference
// Modify through reference
obj3.age = 26;
console.log(obj1.age); // 26 - obj1 also changed!
|
Érték szerinti összehasonlítás:
Ha érték szerint szeretnénk két objektumot összehasonlítani, akkor sajnos (vagy nem) végig kell szépen néznünk a kulcsokat, és megvizsgálni a tartalmazást.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | function objectsEqual(obj1, obj2) {
let keys1 = Object.keys(obj1);
let keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return false;
}
for (let key of keys1) {
if (obj1[key] !== obj2[key]) {
return false;
}
}
return true;
}
let obj1 = {name: "Alice", age: 25};
let obj2 = {name: "Alice", age: 25};
console.log(objectsEqual(obj1, obj2)); // true
|
JSON művletek
A JavaScript Object Notation (JSON) szabványos formátum adatok tárolására és átvitelére:
JSON.stringify() - objektumból string
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | let student = {
name: "Hannah",
age: 21,
grades: [85, 90, 88],
active: true
};
// Convert to JSON string
let jsonString = JSON.stringify(student);
console.log(jsonString);
// {"name":"Hannah","age":21,"grades":[85,90,88],"active":true}
// Pretty print with indentation
let prettyJson = JSON.stringify(student, null, 2);
console.log(prettyJson);
/*
{
"name": "Hannah",
"age": 21,
"grades": [
85,
90,
88
],
"active": true
}
*/
// Save to localStorage (browser)
// localStorage.setItem('student', JSON.stringify(student));
|
JSON.parse() - stringből objektum
| let jsonString = '{"name":"Hannah","age":21,"grades":[85,90,88],"active":true}';
// Convert from JSON string
let student = JSON.parse(jsonString);
console.log(student.name); // "Hannah"
console.log(student.grades); // [85, 90, 88]
// Read from localStorage (browser)
// let student = JSON.parse(localStorage.getItem('student'));
|
Gyakorlati példa: API kommunikáció
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | // Sending data to server
let userData = {
username: "john_doe",
email: "john@example.com",
age: 28
};
// Convert to JSON for sending
let jsonData = JSON.stringify(userData);
// Send jsonData to server via fetch/axios...
// Receiving data from server
let serverResponse = '{"status":"success","userId":12345,"message":"User created"}';
let response = JSON.parse(serverResponse);
if (response.status === "success") {
console.log("User ID: " + response.userId);
}
|
Objektumok tömbökkel
Nagyon gyakori minta, hogy objektumok tömbjeit kezeljük:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | let students = [
{name: "Alice", age: 20, grade: 85},
{name: "Bob", age: 22, grade: 92},
{name: "Charlie", age: 19, grade: 78},
{name: "Diana", age: 21, grade: 95}
];
// Find student by name
let student = students.find(s => s.name === "Bob");
console.log(student); // {name: "Bob", age: 22, grade: 92}
// Filter students with grade > 80
let goodStudents = students.filter(s => s.grade > 80);
console.log(goodStudents);
// Get all names
let names = students.map(s => s.name);
console.log(names); // ["Alice", "Bob", "Charlie", "Diana"]
// Sort by grade (descending)
let sorted = [...students].sort((a, b) => b.grade - a.grade);
console.log(sorted);
|
Úton az objektumorientált paradigma felé
Az object egy hasznos, viszonylag gyakran használt adatszerkezet JavaScriptben.
Ha nem 1 személyünk lenne, hanem mondjuk 100, akkor 100 különböző személy object-et kellene kézzel létrehoznunk, amelyekben külön-külön megadnánk a property-érték párokat.
Ezt persze nem szeretnénk manuálisan elvégezni, így felmerül az igény arra, hogy hozzunk létre egy "blueprint"-et, ami megmondja, hogy hogyan fognak kinézni az objektumaink. Ez a "blueprint" lesz a más nyelvekből ismerős osztály. Ha van egy Person
osztályunk, abból már egyszerűen tudunk személy objektumokat készíteni a példányosítás során.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | // Without classes - repetitive
let person1 = {
name: "Alice",
age: 25,
greet() {
console.log(`Hi, I'm ${this.name}`);
}
};
let person2 = {
name: "Bob",
age: 30,
greet() {
console.log(`Hi, I'm ${this.name}`);
}
};
// With classes - reusable blueprint (következő gyakorlaton)
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hi, I'm ${this.name}`);
}
}
let person1 = new Person("Alice", 25);
let person2 = new Person("Bob", 30);
|
Az osztályokról, illetve az objektumorientáltság JavaScriptben való megvalósításáról a következő gyakorlaton fogunk tanulni.