객체 타입
: 다양한 타입의 값을 하나의 단위로 구성한 복합적인 자료구조이며 변경 가능한 값
: 0개 이상의 프로퍼티로 구성된 집합
: 프로퍼티와 메소드로 구성된 집합체
<역할>
프로퍼티: 객체의 상태를 나타내는 값
메소드: 프로퍼티를 참조하고 조작할 수 있는 동작
→ 상태와 동작을 하나의 단위로 구조화 가능
프로퍼티
: 키와 값으로 구성
var person = {
name: 'Lee',
age: 20
}; //여기에서 'name: 'Lee''와 'age: 20'이 프로퍼티, name/age가 키, 'Lee'/20이 값
키: 빈 문자열을 포함한 모든 문자열 또는 심벌 값
값: js에서 사용할 수 있는 모든 값(함수도 가능)
프로퍼티 값이 함수일 때 = 메소드 (일반 함수와 구분하기 위해
식별자 네이밍 규칙을 준수할 때만 따옴표 생략 가능
키에 문자열/심벌이 아닌 다른 타입이 오면 암묵적 타입 변환됨
키 중복 선언시 덮어쓰기됨
<프로퍼티 키 동적 생성>( [ ] 사용 )
var obj = {};
var key = 'hello';
obj[key] = 'world'; //-> hello: 'world'
객체 리터럴에 의한 객체 생성
: 중괄호 내에 0개 이상의 프로퍼티를 정의 → 변수가 할당되는 시점에 js 엔진이 객체 리터럴을 해석하여 객체 생성
객체 리터럴은 코드 블록과 달리 값으로 평가되기 때문에 뒤에 세미콜론 필수
클래스 정의 후 new와 함께 생성자를 호출할 필요가 없음
프로퍼티 접근
마침표 표기법, 대괄호 표기법
대괄호 표기법에서는 프로퍼티 키를 반드시 따옴표로 감싸줘야 함
객체에 존재하지 않는 프로퍼티에 접근 시 undefined 반환
식별자 네이밍 규칙 준수 X 이름은 무조건 대괄호 표기법 사용
var person = { name: 'Lee' };
//마침표 표기법
console.log(person.name);
//대괄호 표기법
console.log(person['name'];
프로퍼티 값 갱신
이미 존재하는 프로퍼티에 값 할당
프로퍼티 동적 생성
존재하지 않는 프로퍼티에 값 할당
프로퍼티 삭제
delete
연산자 사용
이떄 없는 프로퍼티를 삭제해도 에러 발생 X
var person = {name: 'Lee'};
person.age = 20; //age 동적 생성
delete person.age; //age 프로퍼티 삭제
ES6 확장 기능
1. 프로퍼티 축약 표현
프로퍼티 키가 동일한 이름일 때 프로퍼티 값 생략 가능
//ES5
var x=1, y=2;
var obj = {
x: x,
y: y
};
//ES6
let x=1, y=2;
const obj = {x, y};
2. 계산된 프로퍼티 이름
객체 리터럴 내부에서도 계산된 프로퍼티 키 동적 생성 가능
//ES5
var prefix = 'prop';
var i = 0;
var obj = {};
obj[prefix + '-' + ++i] = i;
obj[prefix + '-' + ++i] = i;
obj[prefix + '-' + ++i] = i;
//ES6
const prefix = 'prop';
let i =0;
const obj = {
[`${prefix}-${++i}`]: i,
[`${prefix}-${++i}`]: i,
[`${prefix}-${++i}`]: i
};
3. 메소드 축약 표현
function
키워드 생략 가능
//ES5
var obj = {
name: 'Lee',
sayHi: function() {
console.log('Hi! ' + this.name);
}
};
//ES6
const obj = {
name: 'Lee',
sayHi() {
console.log('Hi! ' + this.name);
}
};
원시 타입과 객체 타입의 차이
원시 타입 | 객체 타입 | |
---|---|---|
값 변경 | 불가능 | 가능 |
변수 할당 시 변수에 | 실제 값 저장 | 참조 값 저장 |
변수를 다른 변수에 할당 시 | 원시 값이 복사되어 전달(값에 의한 전달) | 원본의 참조 값이 복사되어 전달(참조에 의한 전달) |
원시 값
1. 변경 불가(read-only)
데이터의 신뢰성 보장
원시 값을 변경할 수 없기 때문에 변수에 재할당을 할 때 새로운 메모리 공간 확보 후 재할당한 원시 값을 가리키도록 함 (=불변성)
불변성을 갖는 원시 값을 할당한 변수는 재할당 이외에 변수 값을 변경할 방법이 없음
2. 문자열과 불변성
숫자는 0이든 100이든 동일하기 8byte 필요
but, 문자열은 그 길이에 따라 크기가 달라짐(1글자에 2byte)
다른 언어와 다르게 js는 String을 원시 타입으로 제공 == 변경 불가
유사 배열 객체이면서 이러터블 → 배열과 유사하게 각 문자 접근 가능(그렇다고 변경은 못함)
유사 배열 객체
배열처럼 인덱스로 프로퍼티 값에 접근 가능하고 length 프로퍼티를 갖는 객체
문자열은 원시 타입이나 원시 값을 객체처럼 사용하면 래퍼 객체로 자동 변환 됨
3. 값에 의한 전달
변수1에 변수2 할당 시, 변수2가 가리키는 값이 복사되어 전달됨
∴할당된 이후에 변수2 값 변경 시 변수1에 영향 X
두 변수의 원시 값은 서로 다른 메모리 공간에 저장되어 별개가 되므로 재할당을 통해 값을 변경하더라도 서로 간섭할 수 없다
var score = 80;
var copy = score; //->copy = 80
score = 100; //score과 copy의 값이 달라짐
객체
프로퍼티의 개수가 정해져 있지 않고 동적으로 추가/삭제 가능
∴ 크기를 사전에 정해둘 수 없음
1. 변경 가능한 값
참조 값: 객체가 저장된 메모리 공간 주소
var person = {name: 'Lee'};
에서 {name: 'Lee'}
는 person
이 가리키는 주소가 아닌 다른 주소에 저장되고, person
은 프로퍼티들이 저장된 메모리 주소를 가진다.(=객체를 참조한다)
person
은 객체를 참조 중이므로 객체에 갱신/동적 생성/삭제와 같은 변동 발생 시, 반영 O
여러 식별자가 하나의 객체를 공유할 수 있다는 단점 有
얕은 복사와 깊은 복사
객체를 프로퍼티로 갖는 객체에서
얕은 복사: 한 단계까지만 복사
깊은 복사: 객체에 중첩되어 있는 객체까지 모두 복사
2. 참조에 의한 전달
두 식별자가 하나의 객체를 공유한다는 것은 두 식별자가 저장된 메모리 주소는 다르나 둘 다 동일한 참조 값을 가짐을 의미한다. (다른 프로그래밍 언어에서의 의미와 일치하지 않을 수 있음)
var person1 = {name: 'Lee'};
var person2 = {name: 'Lee'};
console.log(person1 === person2); //①
console.log(person1.name === person2.name); //②
위의 코드에서 두 변수에 따로 객체를 할당했으므로 총 4개의 메모리 주소가 사용되었다.
person1과 person2를 비교하면 최종으로 가리키는 객체가 아니라 참조 값을 비교하므로 ①은 false다.
하지만 프로퍼티 값을 참조하는 person1.name, person2.name의 경우 값으로 평가될 수 있는 표현식이고 두 표현식은 같기 때문에 ②는 true이다.
: 일련의 과정을 문으로 구현하고 코드 블록으로 감싸 하나의 실행 단위로 정의한 것
함수 호출: 인수를 매개 변수를 통해 함수에 전달하여 함수의 실행을 명시적으로 지시하는 것
함수를 사용하는 이유
1. 재사용성
: 한 번 정의한 함수 몇 번이든 호출 가능
2. 유지보수의 편의성, 코드의 신뢰성
: 재사용 → 코드 중복 억제, 실수 ↓
3. 가독성
: 함수 내부 코드를 이해하지 않고도 함수의 역할 파악 가능
함수 리터럴
//변수에 함수 리터럴 할당
var f = function add(x,y) {
return x+y;
};
함수는 객체이나 일반 함수와 달리 호출이 가능하다.
함수 정의
1. 함수 선언문
함수 리터럴과 형태가 동일
함수 선언문은 함수 리터럴과 달리 함수 이름을 생략할 수 있음.
표현식이 아닌 문
function foo() { console.log('foo'); }
foo(); //foo
위의 선언문에서 식별자 foo를 선언한 적 없으나 함수가 잘 호출됨.
js 엔진이 암묵적으로 생성한 식별자이기 때문.
js 엔진은 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의 식별자 생성 후 함수 객체 할당
2. 함수 표현식
표현식인 문
var add = function foo (x, y) {
return x+y;
}; //이때 foo는 호출하면 에러남
함수 호이스팅 불가
3. Function 생성자 함수
바람직하지 않은 방식
var add = new Function('x', 'y', 'return x+y');
console.log(add(2,5)); //7
4. 화살표 함수
항상 익명함수로 정의
함수 선언문이나 표현식에 비해 내부 동작이 간략화되어 있음
생성자 함수로 사용 불가
const add = (x+y) => x+y;
console.log(add(2,5)); //7
함수 호출
식별자와 함수 호출 연산자로 호출
매개변수를 통해 인수를 전달할 때, 매개변수와 인수의 개수가 같은지 확인하지 않음
적으면 적은대로 처리하고 많으면 뒤에껀 무시함.(버려지진 않고 arguments에 보관됨)
인수 확인
단축평가나 매개변수 기본값 사용
//단축평가로 매개변수에 기본값 할당
function add(a, b, c) {
a = a || 0;
b = b || 0;
c = c || 0;
return a + b + c;
}
//매개변수 기본값 사용(매개변수에 인수를 전달하지 않았거나 undefined를 전달했을 때만 유효)
function add(a = 0, b = 0, c = 0) {
return a + b + c;
}
참조에 의한 전달과 외부 상태의 변화
매개변수로 원시 타입을 주면 값에 의한 복사가 되어 원본 훼손 X
반면 매개변수로 객체 타입을 주면 참조에 의한 전달이 되어 원본 훼손 O → 불변객체로 만드는 것을 통해 해결 가능
다양한 함수의 형태
1. 즉시 실행 함수
정의와 동시에 즉시 호출, 1번만 호출 가능
익명함수를 사용하는 것이 일반적(기명함수도 쓸 수는 있음)
(...)로 감싸주기 필수
//즉시 실행 함수
(function () {
//..
}());
//인수 전달도 가능
res = (function (a, b) {
return a*b;
}(3, 5)); //15
2. 재귀 함수, 중첩함수
3. 고차 함수와 콜백 함수
//용례
function repeat(n, f) {
for (var i=0; i<n; i++) {
f(i);
}
} //고차 함수
var logAll = function (i) { console.log(i); }; //콜백 함수
repeat(5, logAll);
고차 함수는 콜백 함수를 자신의 일부분으로 합성
4. 순수 함수와 비순수 함수
순수 함수 : 부수 효과가 없는 함수, 동일한 인수가 들어오면 동일한 값을 반환
비순수 함수 : 부수 효과가 있는 함수, 외부 상태에 따라 같은 인수여도 다른 값 반환(ex. 현재 시간)