자바스크립트는 객체 기반 프로그래밍 언어
원시 값을 제외한 나머지 값은 모두 객체
원시타입 | 객체타입 |
---|---|
단 하나의 값 | 다양한 타입의 값을 하나의 단위로 구성한 복합적인 자료구조 |
변경 불가능 | 변경 가능한 값 |
자바스크립트에서 사용할 수 있는 모든 값 = 프로퍼티 값
객체 = 프로퍼티 + 메서드
0개 이상의 프로퍼티로 구성된 집합
자바스크립트는 객체 지향 언어?
객체 지향 언어 (x) 객체 지향 프로그래밍이 가능한 언어 (o)
함수와 객체는 분리해서 볼 수 없음
클래스 기반 객체지향 언어
인스턴스
클래스에 의해 생성되어 메모리에 저장된 실체
객체 지향 프로그래밍에서의 객체 = 클래스 + 인스턴스
클래스는 인스턴스를 생성하기 위한 템플릿 역할
프로토타입 기반 객체지향 언어
리터럴 : 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기법
객체 리터럴 : {} 를 이용해 0개 이상의 프로퍼티를 정의하며 객체를 생성하는 방법
변수가 할당되는 시점에 자바스크립트 엔진은 객체 리터럴을 해석해 객체를 생성
객체 리터럴의 중괄호 !== 코드 블록 -> 자체 종결성 X 세미콜론을 붙여줘야 함.
객체 리터럴을 제외한 객체 생성 방식은 모두 함수를 사용해 객체를 생성
프로퍼티 키 : 빈 문자열을 포함하는 모든 문자열 또는 심벌 값
minjuKim : 15 ✅
minju kim : 15 ❌
"minju-kim" : 15 ✅
obj[key] = minju // key = kim 이라는 변수일 때 {kim : minju} 객체 생성
프로퍼티 값 : 자바스크립트에서 사용할 수 있는 모든 값
-> 내장함수도 메서드
프로퍼티는 쉼표로 구분
프로퍼티에 접근하는 방법
1. 마침표 프로퍼티 접근 연산자(.) : 마침표 표기법
2. 대괄호 프로퍼티 접근 연산자([]) : 대괄호 표기법
대괄호 안에 들어가는 키는 무조건 따옴표로 감싸줘야함
감싸지 않고 참조하는 경우 식별자로 해석
객체에 존재하지 않는 프로퍼티 접근 시 undefined
반환
프로퍼티 키가 식별자 네이밍 규칙을 준수하는 경우
-> 두 표기법 모두 사용 가능
-> 아닌 경우, 대괄호 표기법만 사용 가능 (숫자로 이뤄진 문자열인 경우 제외)
❌
person.1
person.'1'
✅
person.[1]
person.['1']
person.last-name
node.js -> ReferenceError
브라우저 -> NaN (혹은 window 프로퍼티에 저장된 name 값)
person.last-name의 변수에 따옴표가 없는 경우, person 객체의 프로퍼티인 last에서 name이라는 변수를 빼는 코드(person.last - name)로 해석됨.
person.last 라는 객체가 없다면 undefined를 리턴하고, name이라는 변수를 찾기 시작함
이 때, node환경에서는 name이라는 변수가 없으니 에러가 발생하지만
브라우저 환경에서는 window객체에 name이라는 프로퍼티가 존재
해당 프로퍼티는 문자열이지만 - 숫자 연산자를 사용했으니 name 변수는 암묵적으로 숫자형으로 치환 - 하지만 숫자데이터가 아니니 결과값으로 NaN 출력
이미 존재하는 프로퍼티에 값 할당 -> 값 갱신
존재하지 않는 프로퍼티에 값을 할당 -> 동적으로 프로퍼티 생성
delete 연산자를 이용해 프로퍼티 삭제 가능
let person = {
name : "minju"
}
console.log(person.name) //minju
delete person.name;
console.log(person.name) // undefined
ES6에서는 프로퍼티 값으로 변수를 사용하는 경우, 변수 이름과 프로퍼티 키가 동일한 이름일 때 키를 생략할 수 있음
let x = 1, y = 2;
const obj = {x, y};
console.log(obj) // {x : 1, y : 2};
프로퍼티 키를 동적으로 생성하기 위해서
let i = 0;
obj["serial-" + ++i] = i; // es5
obj[`serial-${++i}`] = i; // es6
let obj = {
func1 : function() {
console.log("es5 grammar")
}
func2() {
console.log("es6 grammar")
}
}
위 예시처럼 es6 문법에서는 메서드를 축약형으로 할당 가능함.
이렇게 선언한 문법은 es5에서 프로퍼티에 함수를 할당하는 방식과 다르게 동작
원시 타입 | 객체 타입 |
---|---|
변경 불가능한 값 | 변경 가능한 값 |
실제 값이 저장 | 참조값이 저장 |
다른 변수에 할당 시 원시 값이 복사되어 저장 | 참조값이 복사되어 저장 |
값에 의한 전달 | 참조에 의한 전달 |
한 번 생성된 원시값은 읽기 전용 값으로 변경될 수 없음
변수 값 변경의 의미
1. 원시 값을 재할당
2. 새로운 메모리 공간을 확보하고 재할당한 값을 저장
3. 변수가 참조하던 메모리 공간의 주소가 바뀜 (불변성)
따라서, 불변성을 갖는 원시 값을 할당한 변수는 재할당 이외에 변수 값을 변경할 수 있는 방법이 없음.
원시 값을 저장하려면 확보해야 하는 메모리 공간의 크기를 결정해야 함
문자열은 다른 원시값과 달리 문자열이 구성된 문자의 갯수에 따라 메모리 공간의 크기가 결정됨. -> 자바스크립트는 개발자의 편의를 위해 원시 타입의 문자열 타입 제공
문자열은 유사배열객체이면서 이터러블 -> 배열과 유사하게 접근 가능
하지만 원본 데이터를 변경하는 것은 안됨 (재할당은 가능)
유사배열객체
- 배열처럼 인덱스로 접근 가능
- length 프로퍼티를 가짐
변수에 원시값을 갖는 변수를 할당
-> 할당받는 변수에는 할당되는 변수의 원시 값이 복사되어 전달
= 값에 의한 전달
같은 값을 가지더라도 다른 메모리 공간에 저장된 별개의 값...?
같은 원시값을 참조하다가 한 변수에 재할당이 이뤄지면 새로운 메모리 공간에 재할당된 값 참조...?
변수에는 값이 전달되는 것이 아닌 메모리 주소가 전달
식별자 = 메모리 주소에 붙인 이름
전달된 메모리 주소를 통해 메모리 공간에 접근해 값을 참조하는 방식
두 변수의 원시값은 서로 다른 메모리 공간에 저장된 별개의 값이 되어 어느 한쪽에서 재할당을 통해 값을 변경하더라도 간섭할 수 없음
객체는 동적으로 프로퍼티가 추가되고 삭제될 수 있기때문에 메모리의 크기를 미리 정할 수 없음.
자바스크립트 객체의 관리 방식
프로퍼티 키를 인덱스로 사용하는 해시테이블 방식 (100%는 아니고 비슷)
이는 객체를 생성하기 전 미리 프로퍼티와 메서드가 정해져 있어 메모리가 픽스되는 클래스 기반 프로그래밍 언어와 다르게 비효율적인 방식
따라서 v8 엔진에서는 프로퍼티에 효율적으로 접근하기 위해 히든 클래스 방식 선택
객체를 할당한 변수가 기억하는 메모리 주소를 통해 메모리 공간에 접근 - 참조값에 접근
참조값 = 객체가 저장된 메모리 공간의 주소
객체를 할당한 변수
여러 개의 식별자가 하나의 객체를 공유할 수 있다는 단점 존재
객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조값이 복사되어 전달
두 개의 객체가 하나의 객체를 공유하기 때문에 한 쪽을 수정하면 다른 한 쪽에도 영향
값에 의한 전달과 참조에 의한 전달
두 방식 모두 식별자가 기억하는 메모리 공간에 대한 주소값을 가지고 있고 그 주솟값이 참조하는 값이 원시값이냐 참조값이냐의 차이만 존재
객체는 타입 관계 없이 다른 메모리 공간에서 참조되기 때문에 동등 비교와 일치 비교와 관계 없이 서로 다른 값