자바스크립트의 거의 모든 것은 객체이다.
객체는 변경가능한 값들을 복합적으로 모은 자료구조이다. 연관된 변수와 함수들을 저장하는 폴더같은 느낌쓰?
{}안에 여러 프로퍼티들(Properties)을 구성하고 그 프로퍼티는 key:value로 나뉜다.{ '키' : '변경가능한 값', ...etc }
모든 값은 프로퍼티의 value가 될 수 있다.
함수도 프로퍼티가 될 수 있다. 이런 경우는 프로퍼티라고 안하고 메서드라고 한다.
OOP(Object-Oriented Programming) 객체 지향 프로그래밍은 이러한 객체들의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임이다.
클래스 기반 객체 지향 언어(C++, JAVA)는 클래스를 먼저 정의하고 객체를 생성한다. 이 때 생성된 객체를 인스턴스(instance)라고 표현한다.
자바스크립트는 프로토타입 기반 객체지향언어로 객체를 생성하는 방법이 다양하다. 방법들은 다음과 같다.
핵심!
key : value로 나눠지고 객체의 일부
key로 사용할 수 있는 값은 문자열 아니면 Symbol()값 (단, 네이밍 규칙을 따르는 식별자인 경우에 한해 ''를 생략할 수 있다. name: "gyujeong")
value는 위에서 말했듯 모든 값
객체에 프로퍼티로 위치한 함수를 부르는 이름
obj = { x: 'x', y: 'z'}
//위의 코드를 아래 코드처럼
obj = { x, y: 'z'}
//이게 무슨 소리냐면
obj = { [`${name}${++i}`]: i, ...etc }
//i가 동적으로 바뀌는 for문 같은 곳에서의 상황에서 key, value 모두에 i를 동적으로 할당할 수 있다는 말
//이거를
obj = { fname: function(){} }
//이렇게 축약 가능
obj = { fname(){} }
이제 위의 두 단어 모두를 안다.
이걸 근데 왜 비교하냐? 헷갈리는 사람들이 많기 때문이다.( 나만 헷갈렸을 수도 있따)
원시값은 변경 불가능한 값이고 객체는 변경 가능한 값이다!
원시값은 실제 값이고 객체는 참조하는 값이다!
원시값은 원본이 복사되고 객체는 참조하는 값이 복사된다!
원시값은 값을 저장할 새로운 메모리 공간을 만들고 객체는 참조값을 저장할 새로운 메모리 공간을 만든다!
C언어는 문자(char) 타입을 배열로 나타내어 문자열을 완성한다. 하지만 Javascript는 문자열이라는 데이터 타입 자체가 존재한다. 이 타입은 원시 타입으로 변경이 불가능하다.
JS의 문자열은 C언어와 똑같지는 않지만 유사배열 객체이다. 그래서 JS에서도 배열과 비슷하게 각 문자에 접근한다. indexing도 하고 길이를 length 프로퍼티로 알 수 있고 등등
이 말은 참조에 의한 전달과 대립되는 말이다. 원시값과 객체를 비교할 때 원시값은 값의 의한 전달을 사용하고 객체는 참조에 의한 전달을 사용한다. JS 정식 용어는 아니고 다른 언어에서 가져온 말이다. 하지만 개념을 이해하기에 좋다.
그래서 값에 의한 전달이 뭐냐면
score = 80; // 80을 가리키는 메모리 공간 할당
copy = score; //copy가 가리키는 메모리 공간이 새로 생긴다.
score = 100;
copy ??; //score를 100으로 재할당해도 copy가 가리키는 새로운 메모리 공간에 80이 있으므로 답은 80
copy => 80
객체는 프로퍼티를 동적으로 추가 제거를 할 수 있다. 따라서 사전에 메모리 공간을 정할 수 없다. 동적으로 할당해야하기 때문에 메모리에 해당하는 비용이 많이 들 수 있다.
JS엔진이 객체를 관리하는 방식부터 알아보자 클래스 기반 객체 지향언어의 인스턴스는 생성된 후에 프로퍼티를 추가 삭제할 수가 없다. JS는 클래스 없이 동적으로 프로퍼티를 생성, 삭제할 수 있다. 하지만 성능 면에서 상대적으로 프로퍼티 접근에 비용이 많이 든다. 그래서 JS엔진이 채택한 방법이 히든 클래스라는 방법이다. 히든 클래스는 Java의 클래스와 유사하게 동작하는데 이는 동적 탐색이라는 상대적으로 비효율적인 방법을 피하기 위한 방법이다.
변수는 메모리 주소를 통해 원시값에 접근한다. 하지만 객체는 메모리 주소를 통해 참조 값에 접근한다. 참조 값은 메모리 주소 그 자체로 식별자가 가리키는 메모리 안에 원시 값이 아니라 메모리 주소가 들어 있는 경우이다!!
원시 값을 할당한 변수는 ~~값을 갖는다라고 말하지만 객체를 할당한 변수는 ~~객체를 참조하고 있다라고 말한다.
이렇게 메모리 안에 메모리 주소가 들어감으로써 생기는 객체의 부작용은 구조적인 단점이다. 그것은 여러개의 식별자가 하나의 객체를 공유할 수 있다는 점이다. 여러 변수에 하나의 객체를 할당하면 n번째 변수를 통해 객체의 프로퍼티 값을 바꿔도 값이 바뀐다!!!!
이 개념은 객체가 중첩되어 있는 경우에 발생한다.
얕은 복사는 첫번째 층의 객체만 복사하는 것으로 전체 객체를 놓고 비교하면 다르지만 그 안의 객체 즉 내부 객체를 가리키는 식별자와 참조값은 같으므로 같다.
깊은 복사는 중첩된 객체 전체를 복사하는 것으로 내부 객체도 다른 참조값을 가지게된다. 그래서 아예 다르다.
다른 변수에 할당하면 얕은 복사는 내부 객체를 공유하게 되지만 깊은 복사는 원시 값처럼 공유하지 못한다.
위에서 값에 의한 전달을 살펴보았었다. 객체는 참조에 의한 전달로 식별자가 하나의 객체를 공유하게된다.
var person = { name : 'Lee' };
var copy;
copy = person
person === copy // true
copy.name = 'Park'
console.log(person.name) // 'Park'