groupBy API

JS에서 어떤 데이터를 표현하는 객체의 형태를 변경하는 일은 매우 자주 있고 이에 대한 코드를 작성하는 것은 한번 정도는 도전 정신이 발휘 되기도 하지만 그 다음부터는 짜증스럽기도 합니다. 아래와 같은 데이터가 있다고 가정해 봅시다.

[
  { name: "Jim", age: 48, sex: "F" },
  { name: "Kyle", age: 28, sex: "M" },
  { name: "Sally", age: 28, sex: "F" },
  { name: "Jane", age: 32, sex: "M" },
  { name: "Tom", age: 48, sex: "F" }
]

이 데이터의 필드 중 sex는 성별을 나타내는 것으로 이를 기준으로 데이터를 다음처럼 구성하려고 합니다.

{
  "F": [
    {"name":"Jim","age":48,"sex":"F"},
    {"name":"Sally","age":28,"sex":"F"},
    {"name":"Tom","age":48,"sex":"F"}
  ],
  "M": [
    {"name":"Kyle","age":28,"sex":"M"},
    {"name":"Jane","age":32,"sex":"M"}
  ]
}

데이터의 표현을 F, M으로 구분해 다시 구성한 형태입니다. 이를 위한 목적을 이루기 위해 JS는 하나의 API 제공하고 있는데 다음과 같습니다.

const people = [
  { name: "Jim", age: 48, sex: "F" },
  { name: "Kyle", age: 28, sex: "M" },
  { name: "Sally", age: 28, sex: "F" },
  { name: "Jane", age: 32, sex: "M" },
  { name: "Tom", age: 48, sex: "F" }
]

const groupBySex = Object.groupBy(people, person => {
  return person.sex
})

Object.groupBy가 핵심인데 이 API는 입력 데이터는 변경하지 않고 새로운 데이터를 만들어 반환합니다.

Javascript에서 객체의 key, value 순회하기

ES6에서 객체의 Key와 Key에 해당하는 Value을 순회하는 코드를 기록해 둡니다.

먼저 순회하려는 객체가 다음과 같다면..

let menus = {
    'menu1': {
        url: 'url(images/menu_icon1.png)',
        title: 'Menu Item 1',
            onclick: function() {
                alert('Menu 1');
            }
        },
    'menu2':  {
        url: 'url(images/menu_icon2.png)',
        title: 'Menu Item 2',
        onclick: function() {
            alert('Menu 2');
        }
    },

    'seprator1':  {},

    'menu3':  {
        url: 'url(images/menu_icon1.svg)',
        title: 'Menu Item 3',
        onclick: function() {
            alert('Menu 3');
        }
    },
    'menu4':  {
        url: 'url(images/menu_icon2.svg)',
        title: 'Menu Item 4',
        onclick: function() {
            alert('Menu 4');
        }
    },
};

순회하는 코드는 다음과 같습니다.

for (let [id, menu] of Object.entries(menus)) {
    if(menu.onclick) {
        this.addMenu(id, menu.url, menu.title, menu.onclick);
    } else {
        this.addSeparator(id);
    }
}

위의 코드에 대한 ES5에서의 동일한 코드는 다음과 같습니다.

for (let id in menus) {
    let menu = menus[id];

    if(menu.onclick) {
        this.addMenu(id, menu.url, menu.title, menu.onclick);
    } else {
        this.addSeparator(id);
    }
}

[JavaScript] 한글인가?, 천단위로 컴마(,) 찍기

자바스크립트로 된 두가지 기능에 대한 함수를 정리해 봅니다. 제 스스로에게는 평소 궁금했던 기능이였고, 매번 구글링을 통해 찾아 정신없이 적용했던 기능이군요.

먼저 해당 문자열이 한글이냐를 판별해 주는 함수입니다.

/* boolean */ function isKoreaWord(/* string */ v) {
    var regExp = /([가-힣])/g;
    var replacedString = v.replace(regExp, '');

    if (replacedString.length == 0) {
        return true;
    } else {
        return false;
    }
}

위의 함수는 정규표현식이라는, 제가 요즘 푹 빠져 살펴보고 있는 기능을 활용한 것입니다. 정규표현식 기능은 상당한 부하(Load)를 가지는 기능인데, 아래의 함수가 더 가볍고 빠르고 적당해 보이는군요.

/* boolean */ function isKoreaWord(/* string */ v) {
    var len = v.length;
    for(var i=0; i<len; i++) {
        var c = v.charAt(i);
        if(c < '가' || c > '힣') return false;
    }

    return true;
}

다음은 숫자에 대해서 천단위로 컴마(,)를 찍어 주는 함수입니다.

/* string */ function addThousandComma(/* number */ v) {
    var regExp = /(^[+-]?\d+)(\d{3})/;
    var sv = String(v);

    while (regExp.test(sv)) {
        sv = sv.replace(regExp, '$1,$2');
    }

    return sv;
}

위 함수들의 출처는 제가 요즘 jQuery 학습을 위해 읽고 또 읽고 오늘도 읽은 윤인성님이 지은 “모던 웹을 위한 JavaScript jQuery 입문”이라는 책입니다.

반복문의 반복 횟수를 줄이는 코드 작성

반복문의 속도를 최적화하기 위한 방법중의 하나로 반복 횟수를 줄이는 것이 있습니다. 이에 대해서 제프 그린버그(Jeff Greenberg)가 제안한 내용이 있는데요. 처음 제안될때 작성된 샘플 코드가 C이지만 이를 JavaScript로 해석해 보았습니다. 먼저 개선해 나갈 반복문의 코드가 다음과 같습니다.

function task(arg) {
    var sum = 0;
    for (var i = 0; i < 10; i++) {
        sum += i;
    }
    return sum;
}

var start = +new Date();
var result = 0;
var repeatCounts = 9999999;

//========================================
for (var i = 0; i < repeatCounts; i++) {
    result += task(i);
}
//========================================

var end = +new Date();
var diff = end - start;
alert("result = " + result + ", " + diff + " msec");

최적화 대상이 되는 반복문은 13ㅡ17번입니다. 반복문 안에서 실해된 코드를 별도의 함수인 task로 뽑아놨습니다. task는 1부터 10까지의 합계를 구하는 간단한 연산을 수행하는 함수입니다. 반복문의 속도를 측정하기 위해서 반복문 앞뒤로 시간을 측정하고 있습니다. 이 반복문을 수행하였더니 제 타블릿PC에서는 8.6초가 나왔습니다. 이제 동일한 결과를 얻으면서도 반복 회수를 줄이는 방식으로 최적화를 한 코드는 다음과 같습니다. 위의 13ㅡ17번에 대한 반복 코드에 대한 변경된 부분만 언급하였습니다.

//========================================
var iters = Math.floor(repeatCounts / 10);
var startAt = repeatCounts % 10;
var i = 0;

do {
    switch (startAt) {
        case 0: result += task(i++);
        case 9: result += task(i++);
        case 8: result += task(i++);
        case 7: result += task(i++);
        case 6: result += task(i++);
        case 5: result += task(i++);
        case 4: result += task(i++);
        case 3: result += task(i++);
        case 2: result += task(i++);
        case 1: result += task(i++);
    }
    startAt = 0;
} while (iters--);
//====================================

한번의 반복으로 최대 10번의 반복을 대신하고 있습니다. switch 문을 보면 break문이 없다는 점을 유념해 해석해 보면 그 원리를 이해할 수 있습니다. 실행해 보면 소요되는 시간이 6.3초로 2.4초 단축된 것을 알 수 있습니다.

Flex에서 Timeline 애니메이션 주기

greenshock의 tween 라이브러리를 사용하여 타임라인 애니메이션을 주는 것에 대해 살펴보았습니다. 요즘 UI 디자인의 추세가 정적인 부분에서는 최대한 Simple하게.. 대신 동적인 효과를 주는 것이기에 추후 고객에게 제공할 시스템에서 적용해볼 요량으로 학습하여 정리해봅니다.

원하는 효과는 다음과 같습니다. 사각형 버튼을 0.4초간 수평으로 화면의 가로 가운데로 이동하고 다시 0.4초간 수직으로 화면의 세로 가운데로 이동한 뒤.. 끝으로 0.3초간 2배 확대하는 애니메이션입니다.

사용자 삽입 이미지
이에 대한 코드는 다음과 같습니다.

TweenPlugin.activate([TransformMatrixPlugin, BezierPlugin]); // 1번만 호출하면 됨

var myTimeline:TimelineLite = new TimelineLite({paused:true}); 
var w:Number = btn.width;
var h:Number = btn.height;

// 화면 중심 이동 및 확대를 위해 화면 크기(300, 300)의 반절값인 150 사용 
myTimeline.append(new TweenLite(btn, 0.4, {x:150-w/2})); 
myTimeline.append(new TweenLite(btn, 0.4, {y:150-h/2}));
myTimeline.append(
    new TweenMax(btn, 0.3, {transformMatrix:{tx:150-w,ty:150-h,scaleX:2, scaleY:2}})
);

myTimeline.play();

간단하게는 사용자 경험(UX)는 사용자에게 사용자 인터페이스(UI)와 동일하게 생각할 수 있습니다. 최근 Windows 8이나 Apple의 iOS의 UI를 살펴보면 과거 입체적인 UI에서 벗어나 보다 평면적인 UI로 디자인되어 있는 것을 볼 수 있습니다. 그러나 이 평면적인 UI에 사용자가 반응을 하게 되면 마치 생명체처럼 움직여 반응하게 됩니다.

UI 및 UX를 가장 효과적으로 학습하는 방법은 이러한 OS의 UI를 살펴보고 사용해 보는 것이 가장 좋다고 생각합니다. 개발자나 디자이너라면.. 이러한 사용에서 끝나는 것이 아니라 자신이 만드는 창작물에도 이러한 배움을 반영해 보는 것이 의미있는 일이라 생각합니다.