연습장

10. Object 객체 본문

JavaScript

10. Object 객체

js0616 2024. 7. 9. 12:31

https://poiemaweb.com/js-object

 

Object | PoiemaWeb

자바스크립트는 객체(object)기반의 스크립트 언어이며 자바스크립트를 이루고 있는 거의 “모든 것”은 객체이다. 원시 타입(Primitives)을 제외한 나머지 값들(함수, 배열, 정규표현식 등)은 모두

poiemaweb.com

 

 

 

1. 객체(Object)란?


자바스크립트는 객체(object) 기반의 스크립트 언어이며, 거의 “모든 것”이 객체이다. 

원시 타입(Primitives)을 제외한 나머지 값들(함수, 배열, 정규표현식 등)은 모두 객체이다.

객체는 키(key)과 값(value)으로 구성된 프로퍼티(Property)들의 집합

  • 데이터를 의미하는 프로퍼티(property)
  • 동작(behavior)을 의미하는 메소드(method)

 

자바스크립트의 객체는 객체지향의 상속을 구현하기 위해 “프로토타입(prototype)”이라고 불리는 객체의 프로퍼티와 메소드를 상속받을 수 있다. 이 프로토타입은 타 언어와 구별되는 중요한 개념이다.

 

 

프로토타입

  • 해당 객체의 기반이 되는 객체로, 다른 객체로부터 상속받은 메서드와 속성을 포함하고 있습니다.
  • 객체에서 어떤 속성이나 메서드를 찾을 때, 해당 객체의 프로토타입 체인을 따라 올라가며 검색합니다.
  • 객체를 직접 복제하거나 확장하지 않고 다른 객체의 프로토타입을 설정함으로써 상속을 구현합니다.

 

// 부모 객체 생성
let animal = {
  eats: true,
  walk() {
    console.log("동물이 걷습니다.");
  }
};

// 자식 객체 생성 및 프로토타입 설정
let rabbit = {
  jumps: true,
  __proto__: animal  // rabbit의 프로토타입을 animal 객체로 설정
};

// rabbit은 animal의 프로퍼티와 메서드를 상속받습니다
console.log(rabbit.eats);  // true
rabbit.walk();  // "동물이 걷습니다."

 

위 예시에서 rabbit 객체는 animal 객체를 프로토타입으로 가지므로, rabbit 객체는 animal 객체의 속성과 메서드를 상속받습니다.

 

 


 

1.1 프로퍼티

  • 프로퍼티는 프로퍼티 키(이름)와 프로퍼티 값으로 구성
  • 프로퍼티 키는 프로퍼티를 식별하기 위한 식별자(identifier)

 

 

키 (key)

  • 빈 문자열을 포함하는 모든 문자열 또는 symbol 값
  • 이외의 값을 지정하면 암묵적으로 타입이 변환되어 문자열이 된다.
  • 중복 선언시 나중에 선언한 프로퍼티로 덮어쓴다. 
  • 객체는 프로퍼티 순서를 보장하지 않는다.

 

가능한 값 (value)

  • 모든 값
  • 프로퍼티 값이 함수일 경우, 일반 함수와 구분하기 위해 메소드라 부른다.

 

2. 객체 생성 방법

 

클래스 기반 객체 지향 언어

  • 클래스를 사전에 정의하고 필요한 시점에 new 연산자를 사용하여 인스턴스를 생성
  • ex) 자바

 

프로토타입 기반 객체 지향 언어

  • 클래스라는 개념이 없고 별도의 객체 생성 방법이 존재한다.
  • ex) 자바스크립트
  • ECMAScript 6에서 새롭게 클래스가 도입되었다.

 

2.1 객체 리터럴

  • {} 내에 1개 이상의 프로퍼티를 기술하면 해당 프로퍼티가 추가된 객체를 생성할 수 있다. 
  • {} 내에 아무것도 기술하지 않으면 빈 객체가 생성된다.

 

var emptyObject = {};
console.log(typeof emptyObject); // object

var person = {
  name: 'Lee',
  gender: 'male',
  sayHello: function () {
    console.log('Hi! My name is ' + this.name);
  }
};

 


 

2.2 Object 생성자 함수

  • new 연산자와 Object 생성자 함수를 호출하여 빈 객체를 생성할 수 있다. 
  • 빈 객체 생성 이후 프로퍼티 또는 메소드를 추가하여 객체를 완성하는 방법이다.

 

생성자(constructor) 함수

  • new 키워드와 함께 객체를 생성하고 초기화하는 함수를 말한다. 
  • 생성자 함수를 통해 생성된 객체를 인스턴스(instance)라 한다. 
  • Object 생성자 함수 이외에도 String, Number, Boolean, Array, Date, RegExp 등의 빌트인 생성자 함수를 제공한다. 
  • 일반 함수와 생성자 함수를 구분하기 위해 생성자 함수의 이름은 파스칼 케이스(PascalCase)를 사용

 

 

프로퍼티 추가

  • 객체가 소유하고 있지 않은 프로퍼티 키에 값을 할당

 

프로퍼티 변경

  • 이미 존재하는 프로퍼티 키에 새로운 값을 할당

 

// 빈 객체의 생성
var person = new Object();
// 프로퍼티 추가
person.name = 'Lee';
person.gender = 'male';
person.sayHello = function () {
  console.log('Hi! My name is ' + this.name);
};

console.log(person.name) // Lee

// 프로퍼티 변경
person.name = 'kim'
console.log(person.name) // kim

 

 

객체 리터럴 방식 {} 으로 생성된 객체는 빌트인(Built-in) 함수인 Object 생성자 함수로 객체를 생성하는 것을 단순화시킨 축약 표현(short-hand)이다. 

 


2.3 생성자 함수


객체를 생성하기 위한 템플릿(클래스)처럼 사용하여 프로퍼티가 동일한 객체 여러 개를 간편하게 생성할 수 있다.

 

 
// 생성자 함수
function Person(name, gender) {
    this.name = name;
    this.gender = gender;
    this.sayHello = function(){
      console.log('Hi! My name is ' + this.name);
    };
  }
 
  // 인스턴스의 생성
  var person1 = new Person('Lee', 'male');
  var person2 = new Person('Kim', 'female');
 
  console.log('person1: ', person1.name); // Lee
  console.log('person2: ', person2.name); // Kim
 

 

 

  • 생성자 함수 이름은 일반적으로 대문자로 시작한다. 
  • 기존 함수와 동일하게 생성자 함수를 선언하고 new 연산자를 붙여서 호출하면 생성자 함수가 된다.
  • 프로퍼티 또는 메소드명 앞에 기술한 this는 생성자 함수가 생성할 인스턴스(instance)를 가리킨다.
  • this에 연결(바인딩)되어 있는 프로퍼티와 메소드는 public(외부에서 참조 가능)하다.
  • 생성자 함수 내에서 선언된 일반 변수는 private(외부에서 참조 불가능)하다.

 

private, 정보은닉

 

// 생성자 함수
function Person(name, gender) {
    this.name = name;
    this.gender = gender;
    this.sayHello = function(){
      console.log('Hi! My name is ' + this.name);
    };

    age = 17 ;

    this.sayAge = function(){
        console.log(age)
    }

    this.setAge = function(newAge){
        age = newAge
    }
  }
 
  // 인스턴스의 생성
  var person1 = new Person('Lee', 'male');
 
  // private 참조 불가능
  console.log('age', person1.age ) ; // undefined
  console.log('obj :',person1); // age 의 존재도 알 수 없음


  // 객체 내부의 메서드를 통해서 age 변수에 접근 가능함
  person1.sayAge(); // 17
 

  // 만약 age 를 다음과 같이 변경하려고 하면
  person1.age = 20 ;  
  person1.sayAge(); // 17  변경되지 않으며
  console.log('obj2 :',person1); // 새로운 age 프로퍼티가 생성된것을 알 수 있음


  // 마찬가지로 메서드를 활용해서 접근 및 변경 가능
  person1.setAge(28);
  person1.sayAge(); // 28

 

 

실험 코드 내용

  • person1.age 로 참조하려고하나 undefined 라 나오며 확인 되지 않는다. 
  • person1 의 객체를 참고해도 해당 age 에 대한 프로퍼티는 확인 되지 않는다. 
  • 객체 내부의 메서드, sayAge를 통해서 age 변수에 접근이 가능하다.
  • person1.age = 값을 할당하면 변경도 되지 않으며 오히려 새로운 age 프로퍼티가 생성된다. 
  • sayAge 를 통해 확인하면 기존의 17 값이 출력되며 
  • 올바르게 변경하기 위해서는 객체 내부의 메서드 setAge 를 활용해야 age 에 접근 가능하다. 

 

private 한 프로퍼티를 변경하기 위해서는 접근 가능한 메서드를 활용해야 한다. 

 

 

 


 

3. 객체 프로퍼티 접근

 

3.1 프로퍼티 키 (key)

  • 일반적으로 문자열(빈 문자열 포함)을 지정한다. 
  • 문자열, symbol, 표현식 이외의 값을 지정하면 암묵적으로 타입이 변환되어 문자열이 된다. 
  • 따옴표('' 또는 "")를 사용하며 유효한 이름의 경우 생략할 수 있다. 
  • ex) first-name에는 반드시 따옴표를 사용해야 하지만 first_name에는 생략 가능
  • 표현식을 프로퍼티 키로 사용하려면 키로 사용할 표현식을 대괄호로 묶어야 한다.
  • var person = {
      [first-name]: 'Kim', // ReferenceError: first is not defined
    };
  • 예약어를 프로퍼티 키로 사용하여도 에러가 발생하지는 않는다.
  • 예상치 못한 에러가 발생할 수 있으므로 쓰지 않도록 해야된다.

 

프로퍼티 값

  • 모든 값과 표현식이 올 수 있으며 프로퍼티 값이 함수인 경우 이를 메소드라 한다.

 

3.2 프로퍼티 값 읽기

 

마침표(.) 표기법과 대괄호([]) 표기법이 있다.

console.log(person.first-name);    // NaN: undefined-undefined
console.log(person[first-name]);   // ReferenceError: first is not defined
console.log(person['first-name']); // 'Kim'

 

 

유효한 이름이고 예약어가 아닌 경우, 프로퍼티 값은 마침표 표기법, 대괄호 표기법 모두 사용가능

유효한 이름이 아니거나 예약어인 경우, 프로퍼티 값은 대괄호 표기법을 사용하며 

대괄호 내에 들어가는 프로퍼티 이름은 반드시 문자열이어야 한다.

 

객체에 존재하지 않는 프로퍼티를 참조하면 undefined를 반환한다.

 


 

3.3 프로퍼티 값 갱신
객체가 소유하고 있는 프로퍼티에 새로운 값을 할당하면 프로퍼티 값은 갱신된다.

 

var person = {
  'first-name': 'Kim',
  'last-name': 'Lee',
  gender: 'male',
};

person['first-name'] = 'Park';
console.log(person['first-name'] ); // 'Park'

 

 

 

3.4 프로퍼티 동적 생성
객체가 소유하고 있지 않은 프로퍼티 키에 값을 할당하면 하면 주어진 키와 값으로 프로퍼티를 생성하여 객체에 추가한다.

 

var person = {
  'first-name': 'Kim',
  'last-name': 'Lee',
  gender: 'male',
};

person.age = 20;
console.log(person.age); // 20

 

 

3.5 프로퍼티 삭제
delete 연산자를 사용하면 객체의 프로퍼티를 삭제할 수 있다. 이때 피연산자는 프로퍼티 키이어야 한다.

 

var person = {
  'first-name': 'Kim',
  'last-name': 'Lee',
  gender: 'male',
};

delete person.gender;
console.log(person.gender); // undefined
 

 

 

3.6 for-in , for-of


for-in

  • 객체의 열거 가능한 속성을 반복적으로 순회할 때 사용합니다.
  • 객체의 속성 순서는 보장되지 않으며, 프로토타입 체인을 통해 상속받은 속성도 포함될 수 있습니다.
  • 순서가 있는 배열 같은곳에 쓰지 않는게 좋음
var person = {
  'first-name': 'Kim',
  'last-name': 'Lee',
  gender: 'male',
};

for (var prop in person) {
  console.log(prop + ': ' + person[prop]);
}

 

 

 

for-of 

  • 배열이나 이터러블 객체의 요소들을 반복적으로 순회할 때 사용합니다.
  • ES6 에서 추가
let arr = [1, 2, 3];

for (let value of arr) {
  console.log(value);  // 1, 2, 3 순서대로 출력됨
}

 

 


 

4. Pass-by-reference
object type을 객체 타입 또는 참조 타입이라 한다. 

 

참조 타입이란 객체의 모든 연산이 실제값이 아닌 참조값으로 처리됨을 의미한다. 

 

원시 타입은 값이 한번 정해지면 변경할 수 없지만(immutable), 

객체는 프로퍼티를 변경, 추가, 삭제가 가능하므로 변경 가능(mutable)한 값이라 할 수 있다.

따라서 객체 타입은 동적으로 변화할 수 있으므로 어느 정도의 메모리 공간을 확보해야 하는지 예측할 수 없기 때문에 런타임에 메모리 공간을 확보하고 메모리의 힙 영역(Heap Segment)에 저장된다.

이에 반해 원시 타입은 값(value)으로 전달된다. 즉, 복사되어 전달된다. 이를 pass-by-value라 한다.

 

// Pass-by-reference
var foo = {
  val: 10
}

var bar = foo;
console.log(foo.val, bar.val); // 10 10
console.log(foo === bar);      // true

bar.val = 20;
console.log(foo.val, bar.val); // 20 20
console.log(foo === bar);      // true

 

foo 객체를 객체 리터럴 방식으로 생성하였다.

이때 변수 foo는 객체 자체를 저장하고 있는 것이 아니라 생성된 객체의 참조값(address)를 저장하고 있다.

 

변수 bar에 변수 foo의 값을 할당하였다.

변수 foo의 값은 생성된 객체를 가리키는 참조값이므로 변수 bar에도 같은 참조값이 저장된다.

즉, 변수 foo, bar 모두 동일한 객체를 참조하고 있다.

 

따라서 참조하고 있는 객체의 val 값이 변경되면 변수 foo, bar 모두 동일한 객체를 참조하고 있으므로 두 변수 모두 변경된 객체의 프로퍼티 값을 참조하게 된다.

객체는 참조(Reference) 방식으로 전달된다. 결코 복사되지 않는다.

 

 

 

 

var foo = { val: 10 };
var bar = { val: 10 };

console.log(foo.val, bar.val); // 10 10
console.log(foo === bar);      // false

var baz = bar;

console.log(baz.val, bar.val); // 10 10
console.log(baz === bar);      // true

 

변수 foo와 변수 bar는 비록 내용은 같지만 별개의 객체를 생성하여 참조값을 할당하였다.

따라서 변수 foo와 변수 bar의 참조값 즉 어드레스는 동일하지 않다.

 

변수 baz에는 변수 bar의 값을 할당하였다.

결국 변수 baz와 변수 bar는 동일한 객체를 가리키는 참조값을 저장하고 있다.

따라서 변수 baz와 변수 bar의 참조값은 동일하다.

 

var a = {}, b = {}, c = {}; // a, b, c는 각각 다른 빈 객체를 참조
console.log(a === b, a === c, b === c); // false false false

a = b = c = {}; // a, b, c는 모두 같은 빈 객체를 참조
console.log(a === b, a === c, b === c); // true true true

 


 

5. Pass-by-value
원시 타입은 값(value)으로 전달된다. 즉, 값이 복사되어 전달된다. 이를 pass-by-value(값에 의한 전달)라 한다. 

원시 타입은 값이 한번 정해지면 변경할 수 없다.

(immutable) 또한 이들 값은 런타임(변수 할당 시점)에 메모리의 스택 영역(Stack Segment)에 고정된 메모리 영역을 점유하고 저장된다.

immutable에 대한 상세한 내용은 객체와 변경불가성(Immutability)을 참조하기 바란다.

 

// Pass-by-value
var a = 1;
var b = a;

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

a = 10;
console.log(a, b);    // 1  10
console.log(a === b); // false

 

 

변수 a는 원시 타입인 숫자 타입 1을 저장하고 있다. 원시 타입의 경우 값이 복사되어 변수에 저장된다.

즉, 참조 타입으로 저장되는 것이 아니라 값 자체가 저장되게 된다.

변수 b에 변수 a를 할당할 경우, 변수 a의 값 1은 복사되어 변수 b에 저장된다.

 

 

 

pass-by-reference 와 비교해보면 같은 코드인데도 값을 전달하는 방식에 따라 다른결과가 나타나는것을 알 수 있다.

 

 

 

 

요약

  Pass-by-Value Pass-by-Reference
전달 방식 값의 복사 주소(참조)의 복사
변경 가능 여부 원시 데이터 타입은 변경 불가능 객체와 같은 복합 데이터 타입은 변경 가능
메모리 저장 위치 스택(Stack) 힙(Heap)
메모리 특성 정적(고정) 동적(가변)

 

 

  • Pass-by-Value (값 전달): 값 자체가 복사되어 전달됩니다. 호출된 함수나 메서드 내에서 해당 값을 변경하더라도 호출자의 변수에는 영향을 주지 않습니다. JavaScript에서는 모든 원시 데이터 타입(숫자, 문자열, 불리언, undefined, null)이 이 방식을 따릅니다.
  • Pass-by-Reference (참조 전달): 변수가 가리키는 객체의 주소(참조)가 복사되어 전달됩니다. 따라서 함수나 메서드 내에서 객체를 변경하면, 호출자의 변수에도 영향을 줍니다. JavaScript에서는 객체와 배열 같은 복합 데이터 타입이 이 방식을 따릅니다.

 


 

6. 객체의 분류

 

Built-in Object(내장 객체)

  • 웹페이지 등을 표현하기 위한 공통의 기능을 제공한다.
  • 웹페이지가 브라우저에 의해 로드되자마자 별다른 행위없이 바로 사용이 가능하다.

 

Host Object(사용자 정의 객체)

  • 사용자가 생성한 객체 들이다. 
  • constructor 혹은 객체리터럴을 통해 사용자가 객체를 정의하고 확장시킨 것들이기 때문에 Built-in Object 와 Native Object가 구성된 이후에 구성된다.

 


 

자바스크립트에서 객체의 특징은?

 

객체 생성 방법은 (3가지)?

 

for-in / for-of 차이점은?

 

pass-by-value / reference 차이점은 ?

 

 

 

 

https://chatgpt.com/

'JavaScript' 카테고리의 다른 글

12. Function 함수  (0) 2024.07.16
11. 객체와 변경불가성(Immutability)  (0) 2024.07.09
9. Type coercion 타입 변환과 단축 평가  (0) 2024.07.08
8. Control Flow 제어문  (0) 2024.07.07
7. Operator 연산자  (0) 2024.07.07