객체는 변수 or 상수를 사용하게 될 때 하나의 이름에 여러 종류의 값을 넣을 수 있게 해줌
변수 or 상수 = {
키 : 값
}
const dog = {
name: '멍멍이',
age: 2
}
console.log(dog.name); // '멍멍이'
console.log(dog.age); // 2
const ironMan = {
name: '토니 스타크',
actor: '로버트 다우니 주니어',
alias: '아이언맨'
};
const captainAmerica = {
name: '스티브 로저스',
actor: '크리스 에반스',
alias: '캡틴 아메리카'
};
function print(hero) {
const text = `${hero.alias}(${hero.name}) 역할을 맡은 배우는 ${hero.actor} 입니다.`
console.log(text)
}
print(ironMan); // 아이언맨(토니 스타크) 역할을 맡은 배우는 로버트 다우니 주니어 입니다.
print(captainAmerica); // 캡틴 아메리카(스티븐 로저스) 역할을 맡은 배우는 크리스 에반스 입니다.
함수에서 파라미터로 받아온 객체 내부의 값을 조회할 때마다
객체.
을 입력하고 있는데
객체 비구조화 할당이라는 문법을 사용하면 코드를 더욱 짧고 보기 좋게 작성 할 수 있음
- 객체 구조분해 라고 불리기도 함
const ironMan = {
name: '토니 스타크',
actor: '로버트 다우니 주니어',
alias: '아이언맨'
};
const captainAmerica = {
name: '스티브 로저스',
actor: '크리스 에반스',
alias: '캡틴 아메리카'
};
function print(hero) {
const { alias, name, actor } = hero;
const text = `${alias}(${name}) 역할을 맡은 배우는 ${actor} 입니다`;
console.log(text)
}
print(ironMan); // 아이언맨(토니 스타크) 역할을 맡은 배우는 로버트 다우니 주니어 입니다.
print(captainAmerica); // 캡틴 아메리카(스티븐 로저스) 역할을 맡은 배우는 크리스 에반스 입니다.
아래의 코드가 객체에서 값들을 추출해서 새로운 상수로 선언해 주는 것
const { alias, name, actor } = hero;
한단계 더 나아가, 파라미터 단계에서 객체 비구조화 할당을 할 수도 있음
const ironMan = {
name: '토니 스타크',
actor: '로버트 다우니 주니어',
alias: '아이언맨'
};
const captainAmerica = {
name: '스티브 로저스',
actor: '크리스 에반스',
alias: '캡틴 아메리카'
};
function print({ alias, name, actor }) {
const text = `${alias}(${name}) 역할을 맡은 배우는 ${actor} 입니다`;
console.log(text)
}
print(ironMan); // 아이언맨(토니 스타크) 역할을 맡은 배우는 로버트 다우니 주니어 입니다.
print(captainAmerica); // 캡틴 아메리카(스티븐 로저스) 역할을 맡은 배우는 크리스 에반스 입니다.
const dog = {
name: '멍멍이',
sound: '멍멍!',
say: function say() {
console.log(this.sound);
}
};
dog.say(); // 멍멍!
함수가 객체안에 들어가게 되면
this
는 자신이 속해 있는 객체를 가르키게 됩니다.
함수를 선언할 때는 이름이 없어도 됩니다. (익명함수)
const dog = {
name: '멍멍이',
sound: '멍멍!',
say: function() {
console.log(this.sound);
}
};
dog.say(); // 멍멍!
ERROR!!!
이유는 function으로 선언한 함수는this
가 제대로 자신이 속한 객체를 가르키게 되는데, 화살표 함수는 그렇지 않기 때문
const dog = {
name: '멍멍이',
sound: '멍멍!',
say: () => {
console.log(this.sound)
}
}
dog.say(); // 멍멍!
const dog = {
name: '멍멍이',
sound: '멍멍!',
say: function() {
console.log(this.sound);
}
};
const cat = {
name: '야옹이',
sound: '야옹~'
}
// cat에 없는 dog의 say함수를 할당함
// 이렇게 되면 say함수의 this가 cat 객체를 인식함
cat.say = dog.say
dog.say(); // 멍멍!
cat.say(); // 야옹~
Getter 함수와 Setter 함수를 사용할 때 객체의 키값들은 중복되면 안되지만
Getter 함수와 Setter함수는 이름이 중복되어도 괜찮음
Getter 함수는 특정 값을 조회(GET)할 때 설정한 함수로 연산된 값을 반환함
Getter 함수는return
이 필수 (반환값이 필요하기 때문)
const numbers = {
a: 1,
b: 2,
get sum() {
console.log('sum 함수가 실행됩니다!');
return this.a + this.b;
}
}
// Getter 함수 호출
console.log(numbers.sum); // 3
numbers.b = 5;
console.log(numbers.sum); // 6
Setter 함수는
파라미터값
이 필수
const dog = {
_name: '멍멍이',
set changeName(value) {
console.log('이름이 바뀝니다..' + value)
this._name = value;
}
}
console.log(dog._name); // 멍멍이
dog.changeName = '뭉뭉이'; // Setter 함수 호출
console.log(dog._name); // 뭉뭉이
Getter 함수는 조회할때 마다 계산
비효율적 <- why?
const numbers = {
_a: 1,
_b: 2,
get sum() {
console.log('sum')
return this._a + this._b;
}
}
console.log(numbers.sum); // 3
numbers.a = 5;
numbers.b = 7;
numbers.a = 9;
console.log(numbers.sum); // sum 16
console.log(numbers.sum); // sum 16
console.log(numbers.sum); // sum 16
Setter 함수는 값이 바뀔때 마다 계산
const numbers = {
_a: 1,
_b: 2,
sum: 3,
calculate() {
console.log('calculate');
this.sum = this._a + this._b;
},
get a() {
return this._a;
},
get b() {
return this._b;
},
set a(value) {
this._a = value;
this.calculate();
},
set b(value) {
this._b = value;
this.calculate();
}
}
console.log(numbers.sum); // 3
numbers.a = 5; // calculate
numbers.b = 7; // calculate
numbers.a = 9; // calculate
console.log(numbers.sum); // 16
console.log(numbers.sum); // 16
console.log(numbers.sum); // 16
getter와 setter를 언급한다면 대부분, private 개념이 따라오게 됨
극단적인 예로는 Private 변수를 지정한 후,
이 변수에 접근하기 위해 getter, setter를 이용한다
class Person {
constructor(name, age) {
this._name = name;
this.age = age;
}
get name() {
return this._name.toUpperCase();
}
set name(newName) {
if(newName) {
this._name = newName;
}
}
}
let man = new Person("John", 10);
console.log(man.name, man.age); // 'JOHN', 10
man.name = "John Park";
man.age = 20;
console.log(man.name, man.age); // 'JOHN PARK', 20
_name
에 직접 접근하지 않으면서, 정의된 오퍼레이션을 통해서만 접근하고 있음 class Time {
constructor(start, end) {
this._start = start;
this._end = end;
this._duration = end - start;
}
}
const time = new Time(0, 20)
time._start = 5;
time._duration -= 5;
console.log(time._start);
위의 경우
start
변수의 값을 수정할 때, 사실상duration
변수도 수정되어야하기 때문에 위와 같은 코드가 됨
이 경우 변수의 직접 접근을 통해 보호되지 못함
그 결과, 누구나 접근하여 변경할 수 있기에,start
에 따른 duration 값이 맞지 않는 결과가 초래될 수 있음
즉, 변수 관계에 있어, 일관성을 깨뜨리게 됨
class Time {
constructor(start, end) {
this._start = start;
this._end = end;
this._duration = end - start;
}
setStart(newStart) {
this._start = newStart;
this._duration = this._end = this._start;
}
getStart() {
return this._start;
}
}
const time = new Time(0, 20);
time.setStart(5);
console.log(time.getStart()); // 5
Getter & Setter를 통해 접근함으로써 변수를 보호할 수 있음
또한 Setter를 통해start
와duration
을 설정함으로써, 위에서 발생한 일관성 문제를 해결할 수 있음
JS만의 Getter & Setter는 변수에 직접 접근하는 것처럼 보이지만 내부적으로는 아님
class Time {
constructor(start, end) {
this._start = start;
this._end = end;
this._duration = end - start;
}
set start(newStart) {
this._start = newStart;
this._duration = this._end = this._start;
}
get start() {
return this._start;
}
}
const time = new Time(0, 20);
time.start = 5;
console.log(time.start); // 5
이전에 배운 객체는 한 변수 혹은 상수에 여러가지 정보를 담기 위함이었다면
배열은 여러개의 항목들이 들어있는 리스트와 같음
const array = [1, 2, 3, 4, 5];
객체 배열
const objects = [{ name: '멍멍이' }, { name: '야옹이' }];
const objects = [{ name: '멍멍이' }, { name: '야옹이' }];
console.log(objects); // [Object, Object]
console.log(objects[0]); // Object {name: '멍멍이'}
console.log(objects[1]); // Object {name: '야옹이'}
배열에 새로운 항목을 추가할 때는 배열이 지니고 있는 내장 함수인
push
함수를 사용
const objects = [{ name: '멍멍이' }, { name: '야옹이' }];
objects.push({
name: '멍뭉이'
});
console.log(objects); // [Object, Object, Object]
배열의 크기를 알아낼 때는 배열의
length
값을 확인
const objects = [{ name: '멍멍이' }, { name: '야옹이' }]
console.log(objects, length); // 2
objects.push({
name: '멍뭉이'
})
console.log(objects.length); // 3
반복문은 특정 작업을 반복적으로 할 때 사용할 수 있는 구문
for문은 가장 기본적인 반복문
for (let i = 0; i < 10; i ++;) {
console.log(i); // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
}
for (초기 구문; 조건 구문; 변화 구문) {
code
}
while문은 특정 조건이 참이라면 계속해서 반복하는 반복문
for문은 특정 숫자를 가지고 숫자의 값을 비교하고, 증감해주면서 반복을 한다면
while문은 조건을 확인만 하면서 반복을 함
때문에 조건문 내부에서 변화를 직접 주어야 함쉽게 말하면 for은 종료지점을 찍어주지 않아도 되지만
while문은 종료지점을 설정하는 코드를 블록내부에 따로 작성해야됨
let i = 0;
while (i < 10) {
console.log(i);
i ++;
}
for...of
문은 배열에 관한 반복문을 돌리기 위해 만들어진 반복문
보통 배열을 반복할때는 배열 내장함수를 쓰기 때문에 사실상 많이 쓸일은 없다
let numbers = [10, 20, 30, 40, 50]
for (let number of numbers) {
console.log(number); // 10, 20, 30, 40, 50
}
객체를 위한 반복문을 알기 전, 객체의 정보를 배열 형태로 받아올 수 있는 함수을 알고가자
const doggy = {
name: '멍멍이',
sound: '멍멍',
age: 2
}
console.log(Object.entries(doggy)); // [Array[2], Array[2], Array[2]]
console.log(Object.keys(doggy)); // ['name', 'sound', 'age']
console.log(Object.values(doggy)); // ['멍멍이', '멍멍', 2]
[[키, 값], [키, 값]]
형태의 배열로 변환[키, 키, 키]
형태의 배열로 변환[값, 값, 값]
형태의 배열로 변환const doggy = {
name: '멍멍이',
sound: '멍멍',
age: 2
};
for (let key in doggy) {
console.log(`${key}: ${doggy[key]}`); // name: 멍멍이 sound: 멍멍 age: 2
}
반복문 안에서는
break
와continue
를 통하여 반복문에서 벗어나거나, 그 다음 루프를 돌게끔 할 수 있음
for (let i = 0; i < 10; i++) {
if (i === 2) continue; // 해당 경우를 실행하지 않고 다음 루프를 실행
console.log(i);
if (i === 5) break; // 반복문을 끝내기
}
숫자로 이루어진 배열이 주어졌을 때 해당 숫자 배열안에 들어있는 숫자 중 3보다 큰 숫자로만 이루어진 배열을 새로 만들어서 반환하라
function biggerThanThree(numbers) {
let array = [];
for (let number of numbers) {
if (number <= 3) {
continue;
}
array.push(number);
}
return array;
}
const numbers = [1, 2, 3, 4, 5, 6, 7];
console.log(biggerThanThree(numbers)); // [4, 5, 6, 7]
내장함수 이용하기
function biggerThanThree(numbers) {
return numbers.filter((number) => number > 3);
}