Front-End

vsoghlv@naver.com

자바스크립트 객체 2

자바스크립트는 객체(object) 기반 언어이다. 함수, 배열, 정규식 등 원시타입을 제외한 나머지 값들은 모두 객체이다. 객체는 키(key) 와 값(value) 로 구성된 프로퍼티의 집합인데 프로티의 값으로는 자바스크립트에서 사용 가능한 모든 값을 사용할 수 있다.

이때 프로퍼티의 값으로 함수를 사용할 수도 있으며, 이럴 경우 메소드라 부른다. (자바스크립트 함수는 일급 객체) 또한 자바스크립트 객체는 객체지향의 상속 구현을 위해 프로토타입 이라 불리는 객체의 프로퍼티와 메소드를 상속 받을 수 있다.

프로퍼티

프로퍼티는 키와 값으로 구성되는데 이 키로 식별한다. 프로퍼티의 키에는 문자열, 혹은 symbol 값이 들어가야 되는데 이외의 값을 지정하면 암묵적 타입변환으로 문자열로 변환된다.

또한 존재하는 프로퍼티 키에 중복 선언 시 나중에 선언한 프로퍼티가 이전의 값을 덮어씌운다.

메소드

프로퍼티 값이 함수인 경우, 일반 함수와 구분을 위해 메소드라 부른다.

객체 생성 방법

자바스크립트는 프로토타입 기반 객체 지향언어로서 별도의 객체 생성 방법이 존재한다. es6 에서 클래스가 추가되기는 했지만 새로운 객체 지향을 제공하는 것이 아닌 함수일 뿐이다.

1. 객체 리터럴

가장 일반적인 방식으로 {} 를 사용하여 객체를 생성한다. 이때 중괄호 내에 1개 이상의 프로퍼티를 적는다면 이 프로터티가 추가된 객체를 생성한다. 중괄호 안에 아무것도 기술하지 않을 시 빈 객체가 생성된다.

let emptyObj = {};
console.log(typeof emptyObj); //object

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

console.log(person)//{name: "Sun", gender: "male", sayHello: ƒ}
person.sayHello(); //Hi! My name is Sun

2. Object 생성자 함수

new Object() 함수를 호출하여 빈 객체를 생성한 후 프로퍼티, 메소드를 추가하여 객체를 완성하는 방법이다. 생성자 함수를 통해 생성된 객체를 인스턴스라 하는데 이때 생성자 함수의 이름은 파스칼케이스 - 쌍봉낙타 표기법, 전체이름의 첫 문자를 포함한 각 단어의 첫 문자를 대문자로 표시 - 를 사용하는 것이 일반적이다.

let person = new Object();

person.name = 'Sun'
person.gender = 'male'
person.sayHello = function () { 
    console.log('hi,' + this.name) 
}

console.log(person)//{name: "Sun", gender: "male", sayHello: ƒ}
person.sayHello()//hi, Sun

다만 이 방식은 특별한 이유가 없다면 굳이 쓸 일이 별로 없다.

3. 생성자 함수

만약 프로퍼티의 값만 다른 여러개의 객체를 생성할 때 위의 방식들을 사용하면 매우 불편하다. 이때 생성자 함수를 사용하면 클래스를 사용하듯이 동일한 프로퍼티를 가지고 있는 여러 개의 객체를 쉽게 생성할 수 있다.

// 생성자 함수
function Person(name, gender) {
  let age = 29;//private
  this.name = name;//public
  this.gender = gender;//public
  this.sayHello = function(){
    console.log('Hi!' + this.name);
  };
}

// 인스턴스 생성
let person1 = new Person('Sun', 'male');
let person2 = new Person('Kim', 'female');

console.log(typeof person1);//object
console.log(typeof person2);//object
console.log(person1);//Person {name: "Sun", gender: "male", sayHello: ƒ}
console.log(person2);//Person {name: "Kim", gender: "female", sayHello: ƒ}

person1.sayHello();
person2.sayHello();

생성자 함수 이름은 보통 대문자로 시작하며, this 로 연결된 프로퍼티와 메소드는 외부에서 참조가 가능하다. 반면 생성자 함수 내부에서 선언된 일반 변수는 내부에서는 접근이 가능하나 외부에서 접근할 수 없다.

객체 프로퍼티 접근

프로퍼티 키

프로퍼티 키는 일반적으로 문자열로 지정한다. 문자열이 아닌 symbol 값 이외에 다른 값을 지정하면 위에서 말했듯이 암묵적 타입변환이 일어난다. 문자열이기 때문에 따옴표를 사용해야 하는데 생략이 가능하지만 first-name 과 같이 연산자가 있는 등, 몇가지 예외적인 상황에서는 반드시 따옴표를 사용해 줘야 한다. 만약 표현식을 프로퍼티로 사용하려면 [] 로 묶어 줘야 한다.

프로퍼티 값 읽기

객체의 프로퍼티 값에 접근할 때는 . 표기법과 [] 표기법이 있다. 만약 이때 프로퍼티 키가 유효한 자바스크립트 이름이고 예약어가 아닌 경우 둘다 사용이 가능하지만, 유효하지 않은 자바스크립트 이름이 거나 예약어인 경우 대괄호를 이용해 읽어야 한다. - 이때 대괄호 내에 들어가는 프로퍼티 이름은 반드시 문자열이어야 한다.

프로퍼티 값 갱신

객체가 소유하고 있는 프로퍼티에 새로운 값을 할당하면 덮어씌우며 갱신된다.

프로퍼티 동적 생성

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

let person = {};
person.age = 29;
console.log(person.age);//29

프로퍼티 삭제

delete 연산자를 이용해 객체의 프로퍼티를 삭제할 수 있다. 피연산자는 프로퍼티 키여야 한다. 객체 자체를 삭제할 수는 없다.

Pass-by-reference

object type을 객체 타입 또는 참조 타입이라 하는데, 참조 타입이란 객체의 모든 연산이 실제값이 아닌 참조값으로 처리됨을 의미한다.

원시 타입의 경우 값이 정해졌을 때 변경할 수 없지만 객체는 프로퍼티를 변경, 추가, 삭제가 가능하다.

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

이와 달리 원시 타입은 값(value)으로 복사되어 전달되는데 이를 pass-by-value라 한다.

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

위의 foo 와 bar 가 가리키는 val : 10 은 참조값이 다르다.

하지만 만약 bar 이 foo 를 참조했다면 두 값의 참조값은 같다.

let foo = {val:10} 
let bar = foo;
bar.val = 20;
console.log(foo.val)//20

bar 가 foo 를 참조한 상태에서 bar.val 의 값을 변경하니 foo.val 도 변경된 것을 볼 수 있다.