ETC -

형태의 변환

  • -

🙌형태의 변환

안녕하세요 TriplexLab입니다.
이번 시간에는 객체 혹은 문자열을 원하는 형태로 변환하는 것에 대해서 살펴보도록 하겠습니다.

✅ 객체를 문자열로 변환하기

const cartItems = [
    {id: 1, item: '핸드밀', price: 40000, discount: 0,},
    {id: 2, item: 'A4용지', price: 4000, discount: 0,},
    {id: 3, item: '수영복', price: 120000, discount: 0,},
    {id: 4, item: '색연필72색', price: 150000, discount: 0,},
];

👉🏻첫 번째 문제 풀이

const carItemsArray = [];
for(const item of cartItems){
	const row = [];
	for(const [, value] of Object.entries(item)){
		row.push(value);
	}
	cartItemsArray.push(row.join());
}

👉🏻두 번째 문제 풀이

const extractValueInObject = obj => Object
	.entries(obj) //[['id', 1], ['item', '핸드밀'], ['price', 4000], ['discount', 0]]
	.map(([, value]) => String(value)); //['1', '핸드밀', '4000', '0']['2', 'A4용지', '4000', '0']...

const cartItemString = cartItems
	.map(extractValueInObject)
	.join('===');

👉🏻결과

console.log(carItemsArray.join('==='));
console.log(cartItemString);

1,핸드밀,40000,0===2,A4용지,4000,0===3,수영복,120000,0===4,색연필72색,150000,0 //👈🏻결과

✅문자열을 형태가 다른 문자열로 변환하기

👉🏻문제 설명

입력 값으로 공백으로 구분된 단어가 오면 그 공백을 기준으로 우리가 많이 쓰는 낙타 표기법, 카멜 케이스로 변환하는 겁니다.

👉🏻첫 번째 문제 풀이

function convertCamelName(name) {
    let camelName = '';
    for(let i = 0, newSpace = false; i < name.length; i++){
        if(name[i] == ' '){
            newSpace = true;
            continue;
        }
        if(newSpace){
            camelName = camelName + name[i].toUpperCase();
            newSpace = false;
        } else {
            camelName = camelName + name[i].toLowerCase();
        }
    }
    return camelName;
};

👉🏻두 번째 문제 풀이

const simpleCamel = (name, splitter = ' ') => name.split(splitter)
    .map((word, wi) => word.split('')
        .map((c, ci) => wi > 0 && ci === 0 ? c.toUpperCase() : c.toLowerCase())
        .join(''))
    .join('')
// wi > 0은 첫번째 단어 스킵한다.
// ci === 0 공백으로 분할된 맨 앞에 있는 위치라는 의미

👉🏻결과

함수에 인자로 어떠한 문자 든 간에 띄어쓰기 기준으로
두 번째 단어의 첫 번째 알파벳은 무조건 대문자로 나오고, 나머지는 소문자로 나옵니다.

console.log(convertCamelName('YOUN HO SO')); 
console.log(simpleCamel('YOUN hO sO')); 

younHoSo //👈🏻결과
younHoSo //👈🏻결과

✅문자열 변환 고급 기법 - 템플릿

👉🏻 Tagged Template

템플릿 리터럴의 발전된 형태로써, 함수 형태로 사용할 수 있다.

const Div = div`
  font-size: 20px;
  color: ${props => props.active ? 'white' : 'gray'};
  border: none;
`;
div`...` //이것 자체가 문자열을 함수 호출하는 것

문자열을 함수 호출에 반환하는 것처럼 대입문에다가 써 놨어요
이게 바로 Tagged Template이라고 하는 기능입니다.
템플릿 리터럴 앞에 붙어 있는 div은 실제로 함수입니다. (다음과 같은 함수 정의됨)

function div(string, ...fns){
  const flat = s => s.split('\n').join('');

  return function(props){
    return `<div style="${flat(string[0]) + (fns[0] && fns[0](props)) + flat(string[1])}"></div>`;
  }
};

그러면 다음과 같이 뒤쪽에 있는 템플릿 리터럴은 어떻게 작동될까요?
내부적으로 굉장히 복잡한 형태로 작동이 되는데요. 이렇게 작동이 됩니다.

div`
  font-size: 20px;
  color: ${props => props.active ? 'white' : 'gray'};
  border: none;
`

일단 기본적으로 템플릿 리터럴에 넘어가 있는 이 데이터 문자열이 div함수의 첫 번째 인자로 전달이 됩니다.
그리고 나서 달러 브레이스가 올 수 있잖아요.
몇 개 든 간에 올 수 있는데 이 달러 브레이스의 개수만큼 이 뒤쪽 가변 인자…fns로 전달이 됩니다.
현재는 달라 브레이스(${})가 하나만 있으니까 …fns에 하나의 인자만 배열로 전달이 되겠죠.

👉🏻 전체 코드

function div(string, ...fns){
  const flat = s => s.split('\n').join('');

  return function(props){
    return `<div style="${flat(string[0]) + (fns[0] && fns[0](props)) + flat(string[1])}"></div>`; //👈🏻 2
  }
};

const Div = div`
  font-size: 20px;
  color: ${props => props.active ? 'white' : 'gray'}; //👈🏻 3
  border: none;
`;

console.log(Div({active: true})); //👈🏻 1

이해를 돋기 위해서 직접 코드의 흐름을 그려봤습니다.

코드의 흐름

✅객체를 형태가 다른 객체로 변환하기

👉🏻source, target 변환

const sourceObject = {
	a:1,
	b:2,
	c:3,
	d:4,
	e:5
};

const groupInfo = {
	aGroup: ['a', 'd', 'e'],
	bGroup: ['c', 'b']
};

function makeGroup(source, info){
	const merge = (a, b) => ({...a, ...b});
	
	return Object.keys(info) //['aGroup','bGroup']
		.map(group => ({ [group] : info[group] // [ { aGroup: ['a', 'd', 'e'], bGroup: ['c', 'b'] } ]
			.map( k => ({ [k] : source[k] })) // [ { aGroup:[a: 1, d: 4, e: 5], bGroup:[c:3, b:2] } ]
			.reduce(merge, {}) // [ { aGroup: {a: 1, d: 4, e: 5}}, {bGroup:{b:2, c:3} } ]
		}))
		.reduce(merge, {}) // { aGroup: {a: 1, d: 4, e: 5}, bGroup:{b:2, c:3}} 최종결과
}

위에 주석으로 단것과 같이 순차적으로 이루어진다.
이 부분은 한줄한줄 잘 살펴보면 이해가 될 것입니다. 저도 이거 이해하는데 여러 번 반복적으로 봐서 이해가 된 것입니다.

👉🏻결과

console.log(makeGroup(sourceObject, groupInfo))

{ aGroup: {a: 1, d: 4, e: 5}, bGroup: {b: 2, c: 3} } //👈🏻결과

🤩마치며

개인 적으로 생각하기에는 FE개발자라면 이런 객체(object)를 내 맘대로 형태를 변화하는 연습이 가장 중요하다고 생각합니다.
왜냐하면 FE개발자가 서버로부터 데이터를 받으면 내가 원하는 형태의 API가 아닐 가능성이 크기 때문입니다.
물론 프로젝트를 막 시작하면 BE개발자와 현업을 하면서 API를 서로 맞추어서 하면 상관이 없지만 아닐 가능성도 있기 때문에 그렇습니다.
그리고 원시적으로 for, for in...등등 이런것 쓰는것 보단, map, reduce..같이 함수형을 사용하게 되면 선언형 프로그래밍의 특성을 가지고 있어서 코들 읽어가는데 수월합니다. 앞으로 이런식으로 많이 연습을 해야 겠다고 생각이 들었습니다.👏🏻🎉😃🎯

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.