8일차

개발 log·2021년 7월 19일
0

TIL

목록 보기
5/21

객체

객체는 변수 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 발생

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 함수와 Setter함수는 이름이 중복되어도 괜찮음

Getter 함수

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 함수

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 & Setter 예시

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 함수

getter와 setter를 언급한다면 대부분, private 개념이 따라오게 됨
극단적인 예로는 Private 변수를 지정한 후,
이 변수에 접근하기 위해 getter, setter를 이용한다


  1. name을 저장할 때는 정확한 값일 때 저장한다.
  2. name을 가져올 때는 대문자로 된 이름을 얻을 수 있다
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

  1. 위 코드를 보면 실제 데이터인 _name에 직접 접근하지 않으면서, 정의된 오퍼레이션을 통해서만 접근하고 있음
  2. 또한 이름을 얻을 때 사용자는 단순히 이름을 얻을 뿐
  3. 대문자로 가공하는 과정은 내부에서 일어날 뿐임
  4. 즉, 단순히 사용자는 이름을 얻고자 할 뿐, 얻는 과정에 있는 내부적인 일은 신경쓰지 않음(모름)
  5. 이러한 원리가 캡슐화의 이점인 정보 은닉임
  6. 메소드로 접근하는 것처럼 보이지 않기 때문에 외관상에도 좋음

Getter & Setter 일관성 유지에 관한 예시

  • start - 시작하는 시간
  • end - 끝나는 시간
  • duration - 지속되는 시간

예시 1 (Getter, Setter를 쓰지 않고 변수에 직접 접근하는 경우)

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 값이 맞지 않는 결과가 초래될 수 있음
즉, 변수 관계에 있어, 일관성을 깨뜨리게 됨


예시 2 (Getter & Setter를 사용한 경우)

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를 통해 startduration을 설정함으로써, 위에서 발생한 일관성 문제를 해결할 수 있음
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문은 가장 기본적인 반복문

for (let i = 0; i < 10; i ++;) {
    console.log(i); // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
}
for (초기 구문; 조건 구문; 변화 구문) {
    code
}

while

while문은 특정 조건이 참이라면 계속해서 반복하는 반복문
for문은 특정 숫자를 가지고 숫자의 값을 비교하고, 증감해주면서 반복을 한다면
while문은 조건을 확인만 하면서 반복을 함
때문에 조건문 내부에서 변화를 직접 주어야 함

쉽게 말하면 for은 종료지점을 찍어주지 않아도 되지만
while문은 종료지점을 설정하는 코드를 블록내부에 따로 작성해야됨

let i = 0;
while (i < 10) {
    console.log(i);
    i ++;
}

for...of

for...of문은 배열에 관한 반복문을 돌리기 위해 만들어진 반복문

보통 배열을 반복할때는 배열 내장함수를 쓰기 때문에 사실상 많이 쓸일은 없다

let numbers = [10, 20, 30, 40, 50]
for (let number of numbers) {
    console.log(number); // 10, 20, 30, 40, 50
}

for...in (객체를 위한 반복문)

객체를 위한 반복문을 알기 전, 객체의 정보를 배열 형태로 받아올 수 있는 함수을 알고가자

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]
  • Object.entries( {Object} ) : [[키, 값], [키, 값]] 형태의 배열로 변환
  • Object.keys( {Object} ) : [키, 키, 키] 형태의 배열로 변환
  • Object.values( {Object} ) : [값, 값, 값] 형태의 배열로 변환

for...in 예시

const doggy = {
  name: '멍멍이',
  sound: '멍멍',
  age: 2
};

for (let key in doggy) {
  console.log(`${key}: ${doggy[key]}`); // name: 멍멍이  sound: 멍멍  age: 2
}

break와 continue

반복문 안에서는 breakcontinue를 통하여 반복문에서 벗어나거나, 그 다음 루프를 돌게끔 할 수 있음

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);
}
profile
개발자 지망생

0개의 댓글