JavaScript

JavaScript 객체

dlwltn98 2023. 3. 6. 20:44

객체 

 - 몇 가지 특수한 기능을 가진 연관 배열(associative array)

 - 원시형(primitive type)과 달리 다양한 데이터를 담을 수 있음

 - 중괄호를 이용해 만들고 프로퍼티(키-값 쌍)를 저장

    ** key : 문자형만 가능

    ** Value : 모든 자료형 가능

 

 

빈 객체를 만드는 방법

// 객체 생성자 문법
let user = new Object();

// 객체 리터럴 문법
let user = {};

 

객체 생성

let user = {
	name:"jisu",  // key : value
	age: 10,
	"likes birds" : true  // 복수의 단어는 따옴표로 묶음 
};

 

객체 프로퍼티 사용

 - 점 표기법: 키가 유효한 식별자인 경우에만 사용 가능

    ** 유효한 식별자 - 공백x, 변수 이름 명명규칙 따름

 - 대괄호 표기법 : 키에 어떤 문자열이 있던 상관없이 동작

// 점 표기법 (dot nation)
user.name;             // 프로퍼티 값 읽기
user.isAdmin = true;   // 프로퍼티 값 추가
delete user.age;       // 프로퍼티 삭제


// 대괄호 표기법(square bracket notation)
user["likes birds"];     // 프로퍼티 값 읽기
user["isAdmin"] = true;  // 프로퍼티 값 추가
delete user["isAdmin"];  // 프로퍼티 삭제

 

** 참고

const는 user의 값은 고정하지만 내용은 고정하지 않으므로 상수 객체는 수정될 수 있음

const user = {
	name : "jisu"
}

user.name = "lee jisu";
console.log(user.name);  // lee jisu

 

 - 계산된 프로퍼티 : 프로퍼티 키가 대괄호로 둘러 쌓인 경우

let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {
	[fruit] : 5,  // 변수 fruit에서 프로퍼티 이름을 동적으로 받아옴
};

console.log(bag.apple);  // 5

 

 - 단축 프로퍼티 : 프로퍼티 값을 기존 변수에서 받아와 사용

function makeUser(name, age) {
	return {
		name : name,
		age : age,

		// 프로퍼티 값 단축 구문(property value shorthand)
		name,
		age,
		isAdmin : true // 일반 프로퍼티와 섞어서 사용 가능 
	};
}

let user = makeUser("jisu", 10);

 

 

프로퍼티 존재 확인, 반복문

// 프로퍼티 존재 여부 확인

// undefined와 비교
console.log(user.noSuchProperty === undefined) // true -> 프로퍼티가 존재하지 않음

// in 연산자 확인
console.log("noSuchProperty" in user)  // false
console.log("age" in user)  // true
// for in 반복문 (객체의 모든 키 순회)

for (key in object) { // 기본 문법
	...
}

// 사용 예시
let user = {
	name: "jisu",
	age: 10,
	isAdmin: true,
}

for (let key in user) {
	console.log(key);  // name, age, isAdmin
	console.log(user[key]);  // jisu, 10, true

 

지금까지 위에서 설명한 객체 ⇒ " 순수 객체 (Plain Object) "

 

일반 객체 말고도 다양한 객체 존재함

- Array : 정렬된 데이터 컬렉션을 저장할때 사용
- Date : 날짜와 시간 정보를 저장할때 사용
- Error : 에러 정보를 저장할 때 사용 

 

 

메서드와 this

 - 객체 프로퍼티에 저장된 함수 ⇒ 메서드(Method)

 - 메서드는 this를 사용해 객체 참조 가능

 - 객체 프로퍼티에 함수를 할당해 객체에게 행동할 수 있는 능력 부여

 

메서드 만들기

// 일반적인 방법
let user = {
	name: "jisu",
	ageL 10,
};

// 메서드 생성
user.sayHi = function() {
	console.log("Hello");
};

// 메서드 사용
user.sayHi();  // Hello


// 메서드 단축 구문
user = {
	// 객체 리터럴 안에서 메서드 선언
	sayHi: function() {
		console.log("Hello");
	}
};

//위 코드의 단축 구문
user = {
	sayHi() {  // function 생략해도 됨 
		console.log("Hello");
	}
};

 

this 값은 런타임에 결정됨

 - 함수를 선언할 때 this를 사용할 수 있음

 - 함수가 호출되기 전까지 this에 값 할당 안됨

 - 함수를 객체 프로퍼티에 저장해 object.method()같이 ‘메서드’ 형태로 호출

     ⇒ this는 object를 참조

let user = {
	name: "jisu",
	age: 10,
	sayHi() {
		// this는 user를 나타냄
		console.log("Hello " + this.name);
	}
};

user.sayHi();  // Hello jisu

 

화살표 함수

 - 일반함수와 달리 자신만의 this를 가지지 않음

 - 화살표 함수 안에서 this를 사용하면 외부에서 this 값을 가져옴 

let user = {
	name: "jisu",
	sayHi() {
		let arrow = () => console.log(this.name);
		arrow();
	}
};

user.sayHi();  // jisu

 

 

심볼형

 - 원시형 데이터, 유일무이한 식별자를 만드는데 사용

 - 유일성이 보장되는 자료형 (이름이 같더라도 값이 항상 다름)

// id는 새로운 심볼이 됨
let id = Symbol();

// 심볼에 "id"라는 설명 붙임, 디버깅시 유용
let id = Symbol("id");

 

전역 심볼

 - 이름이 같을때 값도 같길 원할때 사용 (전역 레지스트리 사용)

 ** 전역 심볼 레지스트리(global symbol registry)

     - 전역 심볼 레지스트리 안에 심볼 만듦 → 이름이 동일한 경우 동일한 심볼 반환 

// 이름을 이용해 심볼을 찾음
// 전역 레지스트리에서 심볼을 읽습니다. 
let id = Symbol.for("id"); // 심볼이 존재하지 않으면 새로운 심볼을 만듭니다.

// 심볼을 이용해 이름을 얻음
let sym = Symbol.for("name");
alert( Symbol.keyFor(sym) ); // name

 

 

참조에 의한 객체 복사

 - 객체는 참조에 의해(by reference) 할당되고 복사됨 

 - 복사된 참조를 이용한 모든 작업(프로퍼티 추가·삭제 등)은 동일한 객체를 대상으로 이뤄짐

 

객체와 원시 타입의 차이

// 변수에 객체에 대한 참조값이 저장됨
// 객체에 대한 참조 값 -> 객체에 저장되어 있는 메모리 주소 
let user = {
	name: "Jhon",
}

// 객체가 할당된 변수 복사 -> 객체 복사X, 객체의 참조값 복사
let admin = user;  // 동일 객체에 대한 참조값 저장
// 원시타입 : 값 그대로 저장, 할당되고 복사됨
// message, phrase 각각에 문자열 "Hello"가 저장됨
let message = "Hello";
let phrase = message;

 

참조에 의한 비교

 - 객체 비교 시 동등 연산자( == )와 일치 연산자( === )는 동일하게 동작 

let a = {};
let b = a;  // 참조에 의한 복사

console.log(a == b);  // true
console.log(a === b);  // true


let c = {};
let d = {};
console.log(c == d);  // false

 

객체의 진짜 복사본을 만드는 방법

1. 얕은 복사를 가능하게 해주는 Object.assign 사용

    ** 중첩 객체를 처리하지 못함 

2. 깊은 복사를 가능하게 해주는  _.cloneDeep(obj) 사용 

 

 

new 연산자와 생성자 함수

 

생성자 함수

 - 일반 함수와 기술적 차이 없음

 - 일반 함수와 구분하기 위해 함수 이름 첫글자를 대문자로 씀

 - 반드시 new 연산자와 함께 호출해야 함

    ** new와 함께 호출 → this가 암시적으로 만들어지고 반환됨

 - 유사한 객체를 여러개 만들때 유용

function User(name) {
  // this = {}; (빈 객체가 암시적으로 만들어짐)

  // 새로운 프로퍼티를 this에 추가
  this.name = name;
  this.isAdmin = false;
  this.sayHi = function() {
    console.log( "제 이름은 " + this.name + "입니다." );
  };
  
  // return this; (this가 암시적으로 반환됨)
}

let user = new User("보라");
user.sayHi();  // 제 이름은 보라입니다.

alert(user.name); // 보라
alert(user.isAdmin); // false
// 인수가 없는 생성자 함수는 괄호 생략 가능
let user = new User;

 

 

객체를 원시형으로 변환하기

원시값을 기대하는 내장 함수나 연산자를 사용 → 객체-원시형으로 자동으로 형변환 됨 

특수 객체 메소드 사용 → 형변환을 원하는데로 조절 가능

 

객체-원시형으로의 형변환 (hint 기준)

  ** hint : 목표로 하는 자료형 정도로 이해하면 쉬움

string  - alert()처럼 문자열을 기대하는 연산을 수행할 때 
number  - 수학 연산을 적용하려고 할 때
default  - 드물게 발생
 - 연산자가 기대하는 피연산자를 확실하게 알 수 없을때 발생
 - 내장 객체는 hint가 default일때와 number일때 동일하게 처리함 
// string 
alert(obj);   

// number
let num = Number(obj);
let n = +obj; // 단항 덧셈 연산
let greater = user1 > user2;

//default
// 이항 덧셈 연산은 hint로 `default`를 사용합니다. 
let total = obj1 + obj2;

// obj == number 연산은 hint로 `default`를 사용합니다. 
if (user == 1) { ... };

 

객체-원시형 변환 알고리즘

1. 객체에 obj[Symbol.toPrimitive](hint) 메서드가 있는지 찾고 있다면 호출

2. 1에 해당X, hint가 string일때 →  obj.toString() 또는 obj.valueOf() 호출

3. 1,2에 해당X, hint가 number일때 → obj.valueOf() 또는 obj.toString() 호출

 

⇒ 객체에 Symbol.toPrimitive가 없으면 JS는 아래 규칙에 따라 `toString`이나 `valueOf`를 호출

 - hint가 string인 경우 : toString -> valueOf 순

   ** toString이 있다면 toString을 호출, toString이 없다면 valueOf를 호출

 - 그 외: valueOf -> toString 순

 

let user = {
  name: "John",
  money: 1000,

  [Symbol.toPrimitive](hint) {
    alert(`hint: ${hint}`);
    return hint == "string" ? `{name: "${this.name}"}` : this.money;
  }
};

// 데모:
alert(user); // hint: string -> {name: "John"}
alert(+user); // hint: number -> 1000
alert(user + 500); // hint: default -> 1500

 

** Symbol.toPrimitive (JS 내장 심볼)

  - 목표로 하는 자료형을 명명하는데 사용

  - 이 메서드 하나로 모든 종류의 형변환을 다룰 수 있음

** obj.toString()만 사용해도 모든 형변환을 다룰 수 있음

 

 

출처 : https://ko.javascript.info/

 

'JavaScript' 카테고리의 다른 글

JavaScript 자료구조와 자료형2  (0) 2023.03.14
JavaScript 고차함수  (3) 2023.03.13
JavaScript 자료구조와 자료형1  (1) 2023.03.09
JavaScript 기본 문법 요약  (2) 2023.02.28
JS를 이용하여 간단한 그림판 만들기  (0) 2023.02.21