ES6+ 템플릿 리터럴로 동적인 문자열 만들기



#1 Template literals(템플릿 리터럴)을 사용한 코드



var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and
not ${2 * a + b}.`);
// "Fifteen is 15 and
// not 20."

템플릿 리터럴은 이중 따옴표나 작은 따옴표 대신 백틱(Grave accent)를 사용합니다.

플레이스 홀더 $와 중괄호( ${ expression } )를 사용해 표현식과 그 사이의 텍스트를 함께 전달합니다.

엔터키를 이용해 개행처리까지 가능합니다.



#2 Nesting templates(템플릿 중첩) 코드


예를들어, header태그의 class를 정할때 삼항연산자를 통해 class에 넣을 텍스트를 그대로 출력할 수 있습니다.


먼저 ES5 에서는


var classes = 'header'
classes += (isLargeScreen() ?
'' : item.isCollapsed ?
' icon-expander' : ' icon-collapser');



두번째로 ES2015에서 중첩(nesting)없이 템플릿 리터럴을 사용한 경우


const classes = `header ${ isLargeScreen() ? '' :
(item.isCollapsed ? 'icon-expander' : 'icon-collapser') }`;

${ expression }을 사용해 script를 사용함.


ES2015에서 nested 템플릿 리터럴을 사용한 경우


const classes = `header ${ isLargeScreen() ? '' :
`icon-${item.isCollapsed ? 'expander' : 'collapser'}` }`;

코드 가독성이 많이 높아 진다.



#3 Tagged templates(태그된 템플릿) 코드


tagged template(태그된 템플릿)는 template literals(템플릿 리터럴)의 더욱 발전된 형태입니다.

tagged template(태그된 템플릿)는 함수로 정의된다.

사용방법은 아래와 같이 함수명에 template literals(템플릿 리터럴)을 붙여서 사용한다


// 함수 정의
function taggedFn(strings, ...expressions) { // 1번
return "Something.";
}

const val1 = 12;
const val2 = 34;
const result = taggedFn`first-${val1}-second-${val2}`; // 2번
console.log(result); // 'Something.'

1번에서 taggedFn이라는 tagged template(태그된 템플릿) 함수를 정의한다.

2번에서 taggedFn 함수를 호출한다. 여기서 함수명과 template literals(템플릿 리터럴)을 붙여서 사용하는 점이 우리가 알고 있던 문법과 다르기 때문에 어색할 수 있다.

여기서 template literals(템플릿 리터럴) 표현식( ${ } )을 기준으로 일반 stringsexpressions를 파싱하여 배열로 만들어 매개변수로 넣어 준다.

strings : ['first-', '-second-', '']

expressions : [12, 34]


아래의 여러 가지 예제를 통해 매개변수 strings, expressions 값이 어떻게 파싱되는지 알아보자.


const val1 = 12;
const val2 = 34;

taggedFn`first-${val1}-second-${val2}-third`;    // 1번
// string : ['first-', '-second-', '-third' ];
// expressions : [12, 34] ;

taggedFn`first-${val1}-second-${val2}`;         // 2번
// string : ['first-', '-second-', '' ];
// expressions : [12, 34] ;

taggedFn`${val1}-second-${val2}`;                // 3번
// string : ['', '-second-', '' ];
// expressions : [12, 34] ;

// 함수 정의
function taggedFn(strings, ...expressions) {
console.log(strings.length === expressions.length + 1); // true
}

2번, 3번의 strings 배열값을 자세히 보면 template literals(템플릿 리터럴) 표현식으로 시작거나 또는 끝나면 '' 빈 문자열이 들어가는 것을 확인할 수 있다.

1번, 2번, 3번의 expressions값을 동일하다.

이 결과로 strings 배열의 개수는 expressions 배열의 개수보다 항상 하나 더 많다는 점을 확일할 수 있다.


tagged template(태그된 템플릿)을 활용해 expressions로 전달된 문자열을 HTML strong 태그로 감싸 강조를 하는 함수를 만들어 보자.


function setStrongify(strings, ...expressions) {
return strings.reduce(
(preValue, str, i) => expressions.length === i
? `${preValue}${str}`
: `${preValue}${str}<strong>${expressions[i]}</strong>`
, '');
}

const val1 = 12;
const val2 = 34;
const result = setStrongify`first ${val1} second ${val2}`;
console.log(result);
// first <strong>12</strong> second <strong>34</strong>


tagged template(태그된 템플릿) 함수의 반환값이 꼭 문자열이 아니어도 된다.

참고로 react에서 사용하는 스타일 적용 패키지 styled-components는 tagged template(태그된 템플릿) 함수가 리액트 컴포넌트를 반환한다.



블로그 이미지

steadily

,

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의 속성 gendersex 변수에 할당된다. 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의 genderundefined이기 때문에 defaultnone을 할당한다.

2의 namenull이기 때문에 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 속성명은 존재하지 않으므로 bundefined가 할당된다.


객체 분해 할당에서 계산된 속성명을 활용할 수 있다.


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 ]

이처럼 객체의 속성명 또는 배열의 첫 번째 원소에 값을 할당할 수 있다.

블로그 이미지

steadily

,

ES6+ 향상된 Object, Array (1)


1. 객체와 배열의 생성과 수정을 간편하게.


#1 Shorthand property names (단축 속성명)


Literal Code를 간편하게 작성


const name = 'peter';
const obj = {
gender: 'male',
name, // 이미 정의 된 변수면 변수명 입력 {name: 'peter'}
getName() { return this.name},
// 함수형은 function 키워드 생략 { getName : function(){....}}
}

비교를 통해 어떻게 개선 되었는지 알아보자.


// 기존 함수 정의
function createUser(name, gender) {
return { name: name, gender: gender};
}
// 개선된 방법
function createUser(name, gender) {
return { name, gender};
}

이렇게 단축 속성명을 사용하면 코드 작성도 간편하고 가독성도 좋아진다.


아래와 같이 디버깅 시 많이 개선된 점을 확인할 수 있다.


const name = 'peter';
const gender = 'male';
// 기존방식
console.log('name =' + name, ', gender =' + gender);
// ES6+
console.log({ name, gender }); // { name: 'peter', gender: 'male' }



#2 Computed property names (계산된 속성명)


더 편리하게 동적으로 속성명을 결정할 수 있게 되었다.

계산된 속성명을 사용한 코드와 그렇지 않은 코드를 비교해보자.


function createObj1( key, val ) {
const obj = {};
obj[key] = val;
return obj;
}
function createObj2( key, val ) {
return { [key]: val };
}

계산된 속성명을 사용하면 createObj2 함수처럼 간결하게 작성할 수 있다.


이 기능을 컴포넌트의 상탯값을 변경할 때 사용하면 유용하다.


class CntComponent extends React.Component {
state = {
cnt1: 0,
cnt2: 0,
cnt3: 0,
};
// ...
onClick = idx => {
const key = `cnt${idx}`;
const val = this.state[key];
this.setState({ [key]: val + 1 }); // 1
}
}

1번에서 복잡해질수 있는 코드를 계산된 속성명을 사용하여 간결하게 작성하였다.




블로그 이미지

steadily

,