ES6+ 향상된 Object, Array (2)
2. 간편하게 객체와 배열 속성값 가져오기.
#1 Spread operator (전개 연산자)
객체의 모든 속성을 꺼내어 나열하여 사용할 때 사용하는 문법이다.
Math.max(2, 5, 10); // 1
const numArr = [1, 2, 5, 6, 9];
Math.max(...numArr); // 2
1번의 방식은 한번 작성하고 나면 동적으로 변경할 수 없다.
하지만 2번에서는 전개 연산자를 사용하여 얼마든지 동적으로 변경된 객체를 매개변수로 전달할 수 있다.
이는 객체나 배열을 복사할 때도 유용하다.
const array1 = [1,2,4];
const object1 = { gender: 'Male', name: 'Peter'};
// 원본 객체를 전개하여 새로운 객체 생성
const array2 = [...array1];
const object2 = { ...object1};
// 속성을 수정하여도 원본 객체에 영향을 주지 않는다.
array2.push(9);
object2.gender = 'Female';
* 배열 = 전개 연산자를 사용해도 그 순서는 유지된다.
console.log( [1, 2, ...[3,4,5], 6] ); // [1,2,3,4,5,6]
new Date( ...[2020,10,12] );
// Thu Nov 12 2020 00:00:00 GMT+0900 (Korean Standard Time)
Date 함수처럼 정의된 매개변수를 순서대로 입력해야 할 때 유용하게 사용할 수 있다.
전개 연산자를 사용하여 서로 다른 두 배열 또는 두 객체를 쉽게 합칠 수 있다.
const object1 = { gender: 'Male', name: 'Peter'};
const object2 = { age: 21 };
const object3 = { ...object1, ...object2};
console.log(object3); // {gender: "male", name: "peter", age: 21}
이때 객체 리터럴에서 속성명이 중복된다면...
ES5까지는 에러가 발생했으나 ES6부터 허용된다.
const object1 = { a: 1, a: 3, b: 4, c: 5};
// { a: 3, b: 4, c: 5 }
const object2 = { ...object1, c: 7 };
// { a: 3, b: 4, c: 7 }
중복 시 최종 결과는 마지막 속성 명의 값이 된다.
* 전개 연산자를 활용하면 원본 객체에 영향을 주지 않고, 특정 속성값 (c: 7)을 변경하고 새로운 객체를 만들어 낼 수 있다.
이는 수정 불가능 변수를 관리할 때 유용하게 사용된다.
#2 Array destructuring assignment(배열 분해 할당)
배열의 여러 속성값을 변수로 분해하여 쉽게 할당할 수 있는 문법이다.
배열 분해 할당 예제를 살펴보자.
const arr = [1, 2];
const [a, b] = arr; // 배열의 속성값을 순서대로 할당한다.
console.log(a); // 1
console.log(b); // 2
다음과 같이 이미 정의된 변수에도 할당이 가능하다.
let a, b;
[a, b] = [1, 2];
초기 default 값 설정도 가능하다.
const arr = [99];
const [a = 1, b = 2] = arr;
console.log(a); // 99
console.log(b); // 2
배열 분해 할당을 통해 두 변수의 값을 쉽게 변경 교환할 수 있다.
let a = 10;
let b = 20;
[a, b] = [b, a];
console.log(a); // 20
console.log(b); // 10
배열 분해 할당에서 배열 속성의 순서를 쉼표를 입력해 설정할 수 있다.
const arr = [10, 20, 30];
const [a, , c] = arr;
console.log(a); // 10
console.log(b); // 30
추출한 속성 개수만큼을 제외한 나머지로 새로운 배열을 생성할 수 있다.
const arr = [10, 20, 30];
const [first, ...rest1] = arr;
console.log(rest1); // [20, 30]
const [a, b, c, ...rest2] = arr;
console.log(rest2); // []
위와 같이 배열 분해 할당 시 마지막에 ... 을 통해 변수에 나머지 모든 속성값으로 새로운 배열을 만든다.
또한 나머지가 없으면 빈 배열을 생성한다.
#2 Object destructuring assignment(객체 분해 할당)
객체의 여러 속성값을 변수로 분해하여 쉽게 할당할 수 있는 문법이다.
const obj = { gender: 'Male', name: 'Peter' };
const { gender, name } = obj;
console.log(gender); // male
console.log(name); // peter
객체는 속성명을 그대로 가져와 할당하기 때문에 순서는 중요하지 않다.
따라서 배열 분해 할당에서는 변수명을 변경할 수 있었지만 객체 분해 할당에서는 그대로 사용해야 한다.
const obj = { gender: 'Male', name: 'Peter' };
const { gender, name } = obj; // 1
const { name, gender } = obj; // 2
const { a, b } = obj; // 3
1, 2의 결과는 동일하다. 3은 존재하지 않은 속성명을 사용하여 undefined가 할당 된다.
새로운 변수명에 할당도 가능하다.
const obj = { gender: 'Male', name: 'peter' };
const { gender: sex, name } = obj;
console.log(sex); // 'male'
console.log(gender) // 참조 에러
obj의 속성 gender는 sex 변수에 할당된다. gender라는 변수는 생기지 않고 gender의 값이 sex 변수에 할당된다.
배열 분해 할당처럼 객체 분해 할당에서도 기본값을 정의 할 수 있다.
const obj = { gender: undefined, name: null, age: 21 };
const { gender = 'none', name = 'none', age = 0 } = obj;
console.log(gender); // none 1
console.log(name); // null 2
console.log(age) // 21
1의 gender는 undefined이기 때문에 default 값 none을 할당한다.
2의 name 은 null이기 때문에 null 값을 할당한다. 명심하자.
변수명 사용자 정의와 default(기본값) 설정을 동시에 해보자.
const obj = { gender: undefined, name: 'Peter'};
const { gender: sex = 'none', name} = obj;
console.log(sex); // 'none'
또한 기본값으로 함수의 return 값을 넣을 수 있다.
function getDefaultText() {
console.log('getDefaultText');
return 'none';
}
const obj1 = { gender: undefined, name: 'Peter'};
const { gender = getDefaultText(), name} = obj1;
// 'getDefaultText' 출력
const obj2 = { address: 'Seoul', empNo: 00001 };
const { address = getDefaultText(), empNo} = obj2;
// 'getDefaultText' 출력 되지않음
당연한 결과지만 default 값을 지정할 경우에만 함수가 호출된다.
객체 분해 할당 시 할당되지 않은 값들로 하나의 별도의 개체를 만들 수 있다.
const obj = {gender: 'Male', name: 'Peter', age: 24};
const { name, ...rest } = obj;
console.log(rest); // { gender: 'male', age: 24 }
배열 분해 할당과 비슷한 방식이다.
for of 문 사용 시 객체 분해 할당을 활용해 보자
const userList = [
{ gender: 'Male', name: 'Peter', age: 24},
{ gender: 'Female', name: 'Jane', age: 24},
]
for(const {gender, name} of userList) {
console.log(name + " : " + gender);
}
객체 속 객체도 분해 가능하다.
const obj = { name: 'Peter', friend: { name: 'Jane'} };
const {
name,
friend: { name: friendName },
} = obj;
console.log(name); // 'peter'
console.log(friendName); // 'Jane'
console.log(friend); // 참조 에러
객체 분해 할당을 통해 friendName이라는 변수만 생성된다.
분해 할당을 통해 변수 단위만 정의할 수 있는 것은 아니다. 패턴 단위로 분해 할당이 가능하다.
const [{ prop: a } = { prop: 111 }] = []; // 1
console.log(a); // 111
const [{ prop: b } = { prop: 111 }] = [{}]; // 2
console.log(b); // undefined
1은 배열에서 첫 번째 원소가 { prop: a }이며, 기본값을 { prop: 111 }로 정의했다. 객체 분해할 [ ]의 첫 번째 원소가 없으므로 기본값이 할당된다.
2에서는 객체 분해할 [{ }]의 첫 번째 원소가 {}이며 prop 속성명은 존재하지 않으므로 b는 undefined가 할당된다.
객체 분해 할당에서 계산된 속성명을 활용할 수 있다.
const idx = 1;
const { [`key${idx}`]: valOfIdx } = { key1: 111 };
console.log(valOfIdx); // 111
객체 분해 할당에서 계산된 속성명을 사용할 때에는 반드시 별칭을 입력해야 한다.
별칭은 단순히 변수명만 입력할 수 있는 것은 아니다.
const obj = {};
const arr = [];
({ a: obj.prop, b: arr[0]} = { a: 111, b: true });
console.log(obj); // { prop:111 }
console.log(arr); // [ true ]
이처럼 객체의 속성명 또는 배열의 첫 번째 원소에 값을 할당할 수 있다.