JS | Core 와 ES6+ 한방에 때려잡기_비구조할당(4/5)

sik2·2021년 7월 17일
0

JavaScript

목록 보기
8/11

지난시간에 class에 대해 알아보았습니다. 이번시간에는 ES6+에 추가 된 객체관련 키워드를 알아봅니다.

이번장에서는 비구조화 할당(destructuring assignment)과 spread, rest 키워드에 대해 다루어봅니다.

ES6+ 에서 추가된 강력한 문법중 하나는 비구조화 할당(구조분해)입니다. 사실 단어만 들어보면 뭔가 싶고 어려워 보일텐데 원리는 간단합니다.

객체 안에 있는 값을 추출 해 변수나 상수로 바로 선언하는 문법입니다. 객체 안의 값을 바로 추출해서 쓸수 있으므로 코드가 매우 간결해집니다.

예제 코드를 보자면

객체 프로퍼티를 변수나 상수에 할당하기 위해서 이전에는 아래와 같이 코드를 작성했습니다.


const obj = { a: 1, b: 2 };

const a = obj.a;
const b = obj.b;

console.log(a); // 1
console.log(b); // 2

하지만 비구조화 할당을 하면 아래와 같이 사용할 수 있습니다.

const obj = { a: 1, b: 2 };

const { a, b } = obj; // obj 객체의 값을 추출해서 상수 a, b로 선언

console.log(a); // 1
console.log(b); // 2

함수의 파라미터에서도 비구조화 할당을 할 수 있습니다.

const obj = { a: 1, b: 2 };

function test({ a, b }) { // obj 객체의 값을 추출해서 파라미터 a, b로 선언
  console.log(a);
  console.log(b);
}

test(obj);

만약 객체에 b 값이 주어지지 않았을 경우엔 아래 처럼 기본 값을 비구조 할당시 설정해 줄 수 있습니다.

객체 obj에 b 값이 없는 경우 파라미터에 비구조 할당

const obj = { a: 1 };

function test({ a, b }) {
  console.log(a);
  console.log(b);
}

test(obj);
// 1
// undefined

객체 obj에 b 값이 없는 경우 파라미터에 비구조 할당 시 기본 값 설정

const object = { a: 1 };

function test({ a, b = 2 }) {
  console.log(a);
  console.log(b);
}

test(object);
// 1
// 2

함수의 파라미터 뿐만 아니라 변수나 상수에서도 가능합니다.

const obj = { a: 1 };

const { a, b = 2 } = obj;

console.log(a); // 1
console.log(b); // 2

비구조화 할당시 이름 변경

const iu = {
  age: '28',
  name: '이지은'
};

const realName = iu.name;

console.log(realName ); // 이지은

위와 같이 객체 프로퍼티를 상수에 할당할 수도 있지만

비구조화 할당을 하는 과정에서 선언 할 값의 이름을 변경할 수도 있습니다.

'추출할 객체 key' : '선언할 이름' 으로 이름을 바꿔줄 수 있습니다.

const iu = {
  age: 28,
  name: '이지은'
};

const { name: realName } = iu
console.log(realName); // '이지은'
console.log(iu); // age: 28, name: '이지은' 값이 바뀌진 않는다.

iu객체 안에 있는 name 을 realName 이라고 선언하게 되며 기존 iu 객체 어떤 값도 바뀌지 않습니다.

배열 비구조화 할당

이번엔 배열에서 비구조화 할당을 하는 코드를 알아봅니다.

ES6+ 문법 전에는 아래와 같이 배열의 원소를 선언한 변수에 할당 해주었습니다.

var array = [1, 2];
var one = array[0];
var two = array[1];

console.log(one); //1
console.log(two); //2

하지만 배열 비구조화 할당을 통해 아래 코드로 간결하게 작성할 수 있습니다.

const array = [1, 2];
const [one, two] = array;

console.log(one);
console.log(two);

배열 안에 있는 원소를 다른 이름으로 새로 선언할 수 있습니다.

배열 비구조화에서도 객체와 마찬가지로 기본값 지정이 가능합니다.

const array = [1];
const [one, two = 2] = array;

console.log(one);
console.log(two);

중첩 구조에서 비구조화 할당

여러 객체가 중첩해 있는 구조에서 비구조화 할당을 하는 방법입니다.

여기서 name, nickName, chineseZodiac 값들을 비구조화 할당을 통해 추출하는 방법은?

const deepObject = {
  state: {
    information: {
      name: '광식',
      nickName: ['bbangsik', 'pangsik', 'sik2']
    }
  },
  chineseZodiac: 'monkey'
};

첫번째는 비구조화 할당 문법을 두번 사용하기

const doubleObject = {
  state: {
    information: {
      name: '광식',
      nickName: ['bbangsik', 'pangsik', 'sik2']
    }
  }, 
  chineseZodiac: 'monkey'
};

const { name, nickName } = doubleObject.state.information;
const { chineseZodiac } = doubleObject;

const extracted = {
  name: name,
  nickName: nickName,
  chineseZodiac: chineseZodiac
}

console.log(extracted); // {name: "sik2", languages: Array[3], chineseZodiac: 'monkey'}

+) object-shorthand 문법

객체의 key와 선언된 값이 존재한다면 아래와 같이 축약이 가능합니다.

// 객체의 key와 선언된 값이 존재한다면
const extracted = {
  name: name,
  nickName: nickName,
  chineseZodiac: chineseZodiac
}

// 축약 가능
const extracted = {
  name,
  nickName,
  chineseZodiac
}

두번째 한번에 모두 추출하는 방법

const doubleObject = {
  state: {
    information: {
      name: '신광식',
      nickName: ['bbangsik', 'pangsik', 'sik2']
    }
  },
  chineseZodiac: 'monkey'
};

const {
  state: {
    information: { name, nickName}
  },
  chineseZodiac
} = doubleObject;

const extracted = {
  name,
  nickName,
  chineseZodiac
};

console.log(extracted); // {name: "sik2", languages: Array[3], chineseZodiac: 'monkey'}

한번에 추출한다는 장점이 있지만 코드 가독성이 떨어지는 단점도 있습니다.

spread 와 rest

ES6+에서 추가된 spread, rest 키워드에 대해 알아 봅시다. 두 키워드는 ...이라는 문법 때문에 비슷해 보이지만 전혀 다른 기능을 담당합니다.

spread

사전적 의미는 펼치다, 퍼뜨리다 입니다. 전 객체 혹은 배열 뿌리다(?)는 의미가 더 와 닿습니다.

spread 키워드의 핵심은 기존 객체를 복사해 넣어주는 것입니다. 객체나 배열안에 여러 값이 있으니 복사해서 넣어주는 행위를 뿌리다 펼치다 퍼뜨리다와 비슷해 키워드명의 spread로 한 것 같습니다.

기존에는 아래와 같이 다른 객체 안에 반복되는 프로퍼티가 있더라도 똑같이 코드를 쳐주어야 하는 번거러움이 있었습니다.

const dog = {
  name: '멍멍이'
};

const cuteDog = {
  name: '멍멍이',
  attribute: 'cute'
};

const whiteCuteDog = {
  name: '멍멍이',
  attribute: 'cute',
  color: 'white'
};

console.log(dog);//Object {name: "멍멍이"}

console.log(cuteDog);//Object {name: "멍멍이", attribute: "cute"}

console.log(whiteCuteDog); //Object {name: "멍멍이", attribute: "cute", color: "white"}

또는 아래와 같이 작성할 수도 있었습니다.

const dog = {
  name: '멍멍이'
};

const cuteDog = dog;
cuteDog.attribute = 'cute';

const whiteCuteDog = cuteDog;
whiteCuteDog.color = 'purple';

console.log(dog);
console.log(cuteDog);
console.log(whiteCuteDog);

console.log(dog === cuteDog); //true

하지만 위 코드는 마지막 console.log(dog === cuteDog) 이 true 인 걸 보면 알 수 있듯이 서로 같은 객체를 바라보고 있습니다. 이는 서로가 값에 영향을 줍니다.

spread 문법을 사용하면 다음과 같이 작성 할 수 있습니다. 복사된 새로운 객체가 들어가기 때문에 서로다른 객체를 바라봅니다. 이느 서로가 값에 영향을 주지 않습니다.

const dog = {
  name: '멍멍이'
};

const cuteDog = {
  ...dog,
  attribute: 'cute'
};

const whiteCuteDog = {
  ...cuteDog,
  color: 'white'
};

console.log(dog);//Object {name: "멍멍이"}

console.log(cuteDog);//Object {name: "멍멍이", attribute: "cute"}

console.log(whiteCuteDog); //Object {name: "멍멍이", attribute: "cute", color: "white"}

console.log(dog === cuteDog); //false

+) 덮어쓰기

spread 뒤에 같은 이름의 프로퍼티가 오면 덮어쓰기가 됩니다.

const whiteDog = {
  color: 'white'
};

const blackDog = {
	...whiteDog, 
	color: 'black' //color 값이 덮어써진다.
}

console.log(whiteDog); // Object {color: "white"}

console.log(blackDog); // Object {color: "black"}

//

const yellowDog = {
	color: 'yellow', // 뒤에오는 ...whiteDog이 다시 덮어쓴다.
	...whiteDog
}

console.log(yellow); // Object {color: "white"}

배열에서 spread 연산자

spread 가 등장하기전에는 아래와 같이 concat() 함수를 통해 값을 할당해야 했습니다.

const animals = ['개', '고양이', '참새'];
const anotherAnimals = animals.concat('비둘기');
console.log(animals); // ['개', '고양이', '참새']
console.log(anotherAnimals); // ['개', '고양이', '참새', '비둘기']

spread 연산자를 사용하면 아래와 같이 사용할 수 있습니다.

const animals = ['개', '고양이', '참새'];
const anotherAnimals = [...animals, '비둘기'];
console.log(animals); // ['개', '고양이', '참새']
console.log(anotherAnimals); // ['개', '고양이', '참새', '비둘기']

배열에서 spread 연산자를 여러번 사용 할 수도 있습니다.

const numbers = [1, 2, 3, 4, 5];

const spreadNumbers = [...numbers, 1000, ...numbers];
console.log(spreadNumbers); // [1, 2, 3, 4, 5, 1000, 1, 2, 3, 4, 5]

rest

rest의 사전적의미는 나머지, 여분, 잉여 입니다. 의미에서 볼 수 있듯이 여분의 값을 추출할 때 쓰이는 키워드 입니다.

spread가 뿌린다라면 rest는 모아온다는 키워드입니다.

rest는 객체, 배열, 그리고 함수의 파라미터에서 사용이 가능합니다.

객체에서 rest

const whiteCuteDog = {
  name: '멍멍이',
  attribute: 'cute',
  color: 'white'
};

const { color, ...rest } = whiteCuteDog; //...rest에서 ...test 등 작명은 자유입니다.
console.log(color); // white
console.log(rest);  //Object {name: "멍멍이", attribute: "cute"}

rest 안에 color 값을 제외한 값이 들어있습니다.

rest 는 객체와 배열에서 사용 할 때는 이렇게 비구조화 할당 문법과 함께 사용됩니다.

배열에서의 rest

const numbers = [0, 1, 2, 3, 4, 5, 6];

const [one, ...rest] = numbers;
// const [...rest, last] = numbers; SyntaxError 이렇게는 불가능

console.log(one); // 0
console.log(rest); // [1, 2, 3, 4, 5, 6];

위 코드와 같이 one에 배열의 맨 앞의 값이 할당되고 나머지 값은 ...rest에 할당됩니다.

함수 파라미터에서의 rest

rest 를 함수파라미터에서 사용 할 수도 있습니다.
예를 들어 파라미터에 값을 합쳐서 return 해주는 함수가 있다고 생각 해봅시다.

function returnSum(a, b, c) {
	 return a + b + c;
}

console.log(returnSum(1, 2)); // NaN
console.log(returnSum(1, 2, 3)); // 6
console.log(returnSum(1, 2, 3, 4, 5)); // 6

위 함수는 호출시 파라미터 3개 중 2개만 넣거나 4개 이상을 넣으면 원하는 값을 얻지 못합니다.

이때 ...rest를 통해 아래와 같이 대응 할 수 있습니다.


function returnSum(...rest) {
  let sum = 0;
	rest.forEach(n => { 
		sum += n; 
	});
	return sum;
}

const result = returnSum(1, 2);
console.log(result); //3

const result2 = returnSum(1, 2, 3);
console.log(result2); //6

const result3 = returnSum(1, 2, 3, 4, 5);
console.log(result3); //15

rest 키워드를 활용하면 파라미터 선언 시 들어올 값을 보다 유연하게 대응할 수 있습니다.

함수 인자와 spread

함수를 선언할 때 받는 값을 파라미터라하고 그 함수를 호출할때 넣는 값을 인자라고 합니다.

function subtract(x, y) { // 파라미터 
	return x - y;
}

const numbers = [1, 2];
const result = subtract(numbers[0], numbers[1]); // 인자
console.log(result); // 인자

위 코드는 배열의 인자를 numbers[0], numbers[1] 같이 넣어주고 있지만

이때 아래와 같이 spread를 사용하면 더 간편하게 인자 값을 처리할 수 있습니다.

function subtract(x, y) {
	return x - y;
}

const numbers = [1, 2];
const result = subtract(...numbers);
console.log(result);

아까 rest 예시 코드를 활용해 보자면 인자 값에 배열의 원소를 넣어주는 코드가 있다고 가정합시다.


function returnSum(...rest) {
  let sum = 0;
	rest.forEach(n => { 
		sum += n; 
	});
	return sum;
}

const numbers = [1, 2, 3, 4, 5];
const result = returnSum(
  numbers[0],
  numbers[1],
  numbers[2],
  numbers[3],
  numbers[4]
);
console.log(result); // 15

이런 불편함을 아래와 같이 spread 연산자를 통해 해결할 수 있습니다.

function returnSum(...rest) {
  let sum = 0;
	rest.forEach(n => { 
		sum += n; 
	});
	return sum;
}

const numbers = [1, 2, 3, 4, 5];
const result = returnSum(...numbers);
console.log(result); // 15
profile
기록

0개의 댓글