Programming/JavaScript

[JavaScript] Objects (객체)

inyeong 2024. 9. 29. 05:48

1. Objects (객체) 

Objects(객체)는 관련 데이터와 기능을 저장하는 컨테이너다. 

객체를 이용해 복잡한 데이터 구조를 표현할 수 있다.

 

2. Creating Object Literals (객체 리터럴 생성) 

객체는 다른 데이터 타입처럼 변수에 할당될 수 있고, key-value 쌍으로 이루어진다. 

key는 값을 가지고 있는 메모리 위치를 가리키는 변수 이름이고, 

value는 함수나 다른 객체를 포함하는 모든 데이터 타입이 될 수 있다. 

 

객체 리터럴을 생성하기 위해 { }key : value를 입력한다. 각 key-value는 , 로 구분한다. 

let spaceship = {
	'Fuel Type' : 'diesel',
    	color : 'silver'
    };
 

3. accessing properties (객체 속성 접근)

객체 속성에 접근하는 방법은 두 가지다. 

 

1️⃣ . (dot notation)
객체 이름 뒤에 .을 쓰고, 그 뒤에 속성 이름(key)을 쓴다. 

let spaceship = { 
	homePlanet: 'Earth', 
    	color: 'silver' 
}; 

spaceship.homePlanet;	// 'Earth' 
spaceship.color;	// 'silver' 
spaceship.favoriteIcecream;	// undefined


존재하지 않는 속성에 접근하려 하면 undefined가 반환된다.

 

2️⃣ [ ] (bracket notation)
[ ] 에 속성 이름(키)을 문자열로 전달한다.

키에 숫자, 공백 또는 특수 문자가 포함된 경우 반드시 [ ]를 사용해야 한다.
. 을 사용하면 에러가 발생한다. 

let spaceship = { 
	'Fuel Type': 'Turbo Fuel', 
    	'Active Duty': true, 
    	homePlanet: 'Earth', 
        numCrew: 5 
}; 

spaceship['Active Duty']; // true 
spaceship['Fuel Type']; // 'Turbo Fuel' 
spaceship['numCrew']; // 5

spaceship['!!!!!!!!!!!!!!!']; // undefined


변수를 사용하여 객체의 키를 선택할 때에도 대괄호 표기법을 사용한다. 

let returnAnyProp = (objectName, propName) => objectName[propName]; 

returnAnyProp(spaceship, 'homePlanet'); // 'Earth'


object.propName을 사용하면 propName을 매개변수가 아닌 키로 인식하여, 
'propName'이라는 키를 찾으려고 할 것이다. 

💡고정된 프로퍼티 이름을 사용할 때에는 점 표기법,
     동적인 프로퍼티 이름을 사용할 때에는 대괄호 표기법을 사용한다. 

 

4. property assignment  (객체 속성 할당)

객체는 변경 가능하기 때문에 생성한 후에 수정할 수도 있다. 

새로운 키-값 쌍을 추가하거나, 기존 속성의 값을 변경할 수 있다.

  • 객체에 해당 속성이 이미 존재한다면, 그 속성 값이 새로운 값으로 대체된다. 
  • 해당 속성이 없었다면, 객체에 새로운 속성이 추가된다.
  • const로 선언된 객체는 재할당할 수 없지만, 속성을 변경하거나 새 속성을 추가하는 것은 가능하다.
  •  delete 연산자를 사용하여 객체에서 속성을 삭제할 수도 있다.
const spaceship = {
	type: 'shuttle'
    	'Fuel Type': 'Turbo Fuel', 
     	mission: 'Explore the universe'
}; 

spaceship = {type: 'alien'};	// TypeError: Assignment to constant variable. 
spaceship.type = 'alien';	// type 속성의 값을 'alien'으로 변경 
spaceship.speed = 'Mach 5';	// 새로운 키 'speed'와 값 'Mach 5' 추가
delete spaceship.mission;	// mission 속성을 삭제

 

5. methods (메소드)

객체에 저장된 데이터가 함수일 때, 이를 메서드(method)라고 한다.

속성(property)은 객체가 가지고 있는 것을 의미하며, 메서드는 객체가 하는 일을 나타낸다.

 

객체 리터럴 메서드는 키-값 쌍을 사용하여 작성할 수 있다.

키(key)는 메서드의 이름이 되고, 값(value)은 익명 함수 표현식이 된다.

const alienShip = { invade: function () { 
				console.log('Hello! We have come to dominate your planet.') } 
};

 

콜론과 function 키워드는 생략할 수 있다.

const alienShip = { invade () { console.log('Hello! We have come to dominate your planet.') } };

 

객체 메서드는 객체 이름에 . 연산자를 사용해 메서드 이름과 괄호를 붙여 호출한다.

alienShip.invade(); // 출력: 'Hello! We have come to dominate your planet.'

 

6. nested objects (중첩 객체) 

객체는 또 다른 객체를 속성으로 가질 수 있으며, 그 속성 역시 배열이나 더 많은 객체를 포함할 수 있다.

const spaceship = {
	telescope: { yearBuilt: 2018, 
                 	model: '91031-XLT', 
                 	focalLength: 2032}, 
                    
	crew: { captain: 
    			{ name: 'Sandra', 
               			degree: 'Computer Engineering', 
                		encourageTeam() { console.log('We got this!') } } }, 
         
    	engine: { model: 'Nimbus2000' }, 
    
    	nanoelectronics: { computer: { terabytes: 100, monitors: 'HD' }, 
    				'back-up': { battery: 'Lithium', terabytes: 50 } } 
  };

 

연산자를 연결하여 중첩된 속성에 접근할 수 있다. 

spaceship.nanoelectronics['back-up'].battery; // 'Lithium' 반환

 

7. pass by reference

객체는 참조에 의해 전달된다.

객체를 할당한 변수를 함수의 인수로 전달할 때, 컴퓨터가 해당 매개변수 이름을 그 객체가 저장된 메모리 공간을 가리키는 것으로 해석하여 객체의 속성을 변경하는 함수는 해당 객체를 영구적으로 수정하게 된다. 

const spaceship = { homePlanet: 'Earth', color: 'silver' }; 
let paintIt = obj => { obj.color = 'glorious gold'; }; 
paintIt(spaceship); 
spaceship.color; // 'glorious gold' 반환

 

paintIt() 함수는 spaceship 객체의 color 속성을 영구적으로 변경했다.

하지만 spaceship 변수를 재할당하려고 할 때는 같은 방식으로 작동하지 않는다.

let spaceship = { homePlanet: 'Earth', color: 'red' }; let tryReassignment = obj => { obj = { identified: false, 'transport type': 'flying' }; console.log(obj); // {'identified': false, 'transport type': 'flying'} 출력 }; tryReassignment(spaceship); // 재할당 시도는 작동하지 않음 spaceship; // 여전히 {homePlanet: 'Earth', color: 'red'} 반환 spaceship = { identified: false, 'transport type': 'flying' }; // 일반 재할당은 여전히 작동

 

8. looping through objects

for .. in 구문을 사용하면 객체의 각 속성에 접근하여 코드를 반복 실행할 수 있다. 

let spaceship = { crew: { 
			captain: { 
            			name: 'Lily', 
                    		degree: 'Computer Engineering', 
                    		cheerTeam() { console.log('You got this!') } 
                           	}, 
           		'chief officer': { 
                		name: 'Dan', 
                        	degree: 'Aerospace Engineering', 
                        	agree() { console.log('I agree, captain!') } 
                       	   	}, 
			medic: { 
            			name: 'Clementine', 
                    		degree: 'Physics', 
                    		announce() { console.log(`Jets on!`) } 
                    		}, 
			translator: { 
            			name: 'Shauna', 
            			degree: 'Conservation Science', 
				powerFuel() { console.log('The tank is full!') } 
                		} 
             	} 
 }; 

for (let crewMember in spaceship.crew) { 
	console.log(`${crewMember}: ${spaceship.crew[crewMember].name}`); 
}

/*
captain: Lily 
chief officer: Dan 
medic: Clementine 
translator: Shauna
*/

 

9. this keyword

goat 객체의 속성 dietType을 출력하는 메소드 .diet()를 생성하려고 한다. 

그런데 .diet() 메소드 범위 내에서는 goat 객체의 속성에 접근할 수 없기 때문에 에러가 발생한다. 

const goat = {
    dietType: 'herbivore',
    makeSound() {
    	console.log('baaa');
    },
    diet() {
    	console.log(dietType);
    }
};

goat.diet();	// "ReferenceError: dietType is not defined"

 

this 키워드를 사용하면 이 문제를 해결할 수 있다. 

this 키워드는 호출하는 객체를 참조하며, 호출하는 객체의 속성에 접근할 수 있게 해준다. 

 

this를 사용하면 goat 객체 자체에 접근하여, dietType 속성에 접근할 수 있다. 

const goat = {
  dietType: 'herbivore',
  makeSound() {
    console.log('baaa');
  },
  diet() {
    console.log(this.dietType);
  }
};

goat.diet();	// herbivore

 

메소드에서 호출 객체는 해당 메소드가 속한 객체이다. 

메소드 내에서 this 키워드를 사용하면 this의 값은 호출 객체가 된다. 

const goat = { 
	dietType: 'herbivore', 
    	makeSound() { console.log('baaa'); }, 
        diet: () => { console.log(this.dietType); } 
}; 
    
goat.diet(); // undefined

 

10. privacy 

객체에서 프라이버시(privacy)는 특정 속성만 수정하거나 값을 변경할 수 있도록 하는 것이다. 

자바스크립트에는 객체의 프라이버시 기능이 없기 때문에

속성이 변경되지 말아야 한다는 의미를 전달하는 네이밍 규칙을 따른다. 

 

속성 이름 앞에 _를 붙이는 것이 가장 일반적인 규칙이다.  

const bankAccount = { _amount: 1000 }

 

_amount는 변경되지 말아야 한다는 의미를 전달하고 있지만, _amount를 재할당하는 것은 가능하다.

 

bankAccount._amount = 1000000;

 

11. getters 

 

getter 메서드는 객체의 내부 속성을 가져와 반환하는 역할을 한다.

get 키워드로 메서드를 정의하고, _firstName과 _lastName이 존재하는지 확인한 후 결과에 따라 다른 값을 반환한다.

const person = {
  _firstName: 'John',
  _lastName: 'Doe',
  get fullName() {
    if (this._firstName && this._lastName) {
      return `${this._firstName} ${this._lastName}`;
    } else {
      return 'Missing a first name or a last name.';
    }
  }
}

// Getter 메서드 호출
person.fullName; // 'John Doe'

 

일반적으로 getter 메서드는 속성처럼 호출되므로 괄호가 필요 없다.

속성 이름과 getter 메서드 이름이 같으면 무한 호출 스택 오류가 발생할 수 있으므로 주의한다.

 

12. setters

Setter 메서드는 객체의 기존 속성 값을 다시 할당하는 메서드이다.

const person = { _age: 37, 
		set age(newAge) { 
                	if (typeof newAge === 'number') {	 
                    		this._age = newAge; 
                     	} else { 
                     		console.log('You must assign a number to age'); 
                        } 
                } 
};
person.age = 40; 
console.log(person._age); // 출력: 40 
person.age = '40'; // 출력: You must assign a number to age

 

this._age에 새 값을 할당하기 전에, newAge 값이 숫자인지 확인한다. 

setter 메서드를 통해 숫자 값만 this._age에 재할당될 수 있다. 

 

 setter 메서드는 괄호 없이 속성처럼 호출된다. 

Setter 메서드를 사용하더라도 여전히 객체의 속성에 직접 접근하여 값을 변경할 수 있다. 

 

 

13. factory functions 

객체의 여러 인스턴스를 빠르게 생성해야 할 때 사용하는 것이 팩토리 함수이다.

팩토리 함수는 객체를 반환하고 여러 객체 인스턴스를 생성하는 데 재사용할 수 있는 함수다.

또한, 팩토리 함수에는 매개변수를 사용할 수 있어 반환되는 객체를 사용자 맞춤형으로 만들 수 있다.

const monsterFactory = (name, age, energySource, catchPhrase) => {
  return {
    name: name,
    age: age,
    energySource: energySource,
    scare() {
      console.log(catchPhrase);
    }
  }
};

필요한 인수와 함께 monsterFactory를 호출하고 반환된 값을 변수에 할당하면 ghost 객체를 생성할 수 있다. 

이렇게 하면 새로운 몬스터가 필요할 때마다 객체 리터럴을 만들 필요가 없다. 

const ghost = monsterFactory('Ghouly', 251, 'ectoplasm', 'BOO!');
ghost.scare(); // 'BOO!'

 

14. Property Value Shorthand (속성 값 축약법)

const monsterFactory = (name, age) => {
  return {
    name: name,
    age: age
  }
};

const monsterFactory = (name, age) => { return { name, age } };

15. Destructured Assignment (구조 분해 할당)

const vampire = {
  name: 'Dracula',
  residence: 'Transylvania',
  preferences: {
    day: 'stay inside',
    night: 'satisfy appetite'
  }
};

 

위 코드에서 residence 속성을 변수로 추출하고 싶다면, 다음과 같은 코드를 사용할 수 있다. 

const residence = vampire.residence;
console.log(residence);	// 'Transylvania'

 

이때 구조 분해 할당을 이용하면, 키 입력을 줄일 수 있다. 

객체의 키 이름을 중괄호 { }로 감싸고, 객체에 할당하여 변수를 생성한다. 

const { residence } = vampire; 
console.log(residence); // 'Transylvania'

구조 분해 할당을 사용하면 객체의 중첩된 속성도 추출할 수 있다.

const { day } = vampire.preferences;
console.log(day); // 'stay inside' 출력

 


 

예제 코드 : https://github.com/inyeongjang/Snoopy/blob/main/week03/8-Objects.js

 

Snoopy/week03/8-Objects.js at main · inyeongjang/Snoopy

Contribute to inyeongjang/Snoopy development by creating an account on GitHub.

github.com

 

참고자료https://www.codecademy.com/enrolled/courses/introduction-to-javascript

 

Learn JavaScript | Codecademy

Begin your web development journey with our JavaScript course. Explore dynamic scripting for interactive web solutions.

www.codecademy.com