[es6] 연구노트 #1 – 명확한 코드

개요

s67에서는 ES2015를 주제로 스터디를 전개했습니다. 그 때의 내용을 정리하여 포스팅하는 시리즈입니다. ES2015에 대한 제 개인적인 이해와 정보를 정리해봅니다.

기본형의 명확한 정의

자바스크립트는 기본으로 제공하는 코어객체와 타입이 몇 개 되지 않습니다. 하지만 이마저도 암묵지가 많아 언어적인 표현이 명확하지 않고 숙련된 언어 사용자만이 의미를 파악할 수 있는 경우가 많습니다. 따라서 이를 명확하게 사용하도록 언어차원에서의 유도를 제공합니다.

Boolean

자바스크립트에서는 “”, 0, false, undefined, null, NaN 등이 식에서 거짓으로 평가됩니다. 이를 악용(선용?)하여 굳이 Boolean형을 사용하지 않는 경우가 많습니다. 다음과 같은 C스타일의 코드가 난무하는 현실입니다.

function(){
  if(arguments.length){ //인자가 있다면의 뜻으로 사용됨
  }
}
function(v){
  if(v.trim()){ //빈 문자열이나 공백만 갖고 있는 문자열이 아니면이라는 뜻으로 사용됨
  }
}

이는 사용자가 만든 코드에서만 유도되는 것이 아니라 코어객체의 메소드에서도 자연스럽게 유도됩니다.

if(str.indexOf(token) > -1){ //-1보다 크다를 포함여부로 사용함
}

즉 boolean사용을 명확히 하는 케이스를 유도하지 않고 편법적인 사용을 유도하게 됩니다. 자바스크립트의 언어스펙을 굉장히 자세히 알고 있지 않은 개발자에게는 굉장히 암호처럼 보일 수 있는 표현입니다. 이러한 표현을 코어객체의 메소드에서부터 차근차근 수정하려는 움직임이 있습니다. 따라서 코어객체의 메소드에 명확한 boolean기반으로 판정 메소드를 추가하게 됩니다.
아래의 예에서는 기존 ES에서 편법적으로 사용되던 방법을 명확한 boolean메소드로 재정의한 es2015의 기능을 볼 수 있습니다.

//정수판단
if(v === parseInt(v, 10)){}
if(Number.isInteger(v)){}

//경계값판단
if(v === v + 1 || v === v - 1){}
if(Number.isFinite(v)){}

//문자열내포
str = 'abcd';
if(str.indexOf('c') > -1){}
if(str.include('c')){}

//시작문자열 끝문자열판단
if(str.substr(0,3) == 'abc'){}
if(str.startsWith('abc')){}

if(str.substr(str.length - 3) == 'bcd'){}
if(str.endsWith('bcd')){}

이러한 코어객체의 메소드들은 기존 버전으로 폴리필 될 수 있다 아니다가 중요한 점이 아닙니다. 표준 스펙상에서 boolean에 대한 사용을 바르게 유도함으로서 언어차원에서 가부판정에는 boolean이 사용되도록 역할을 명확히 해준다는 점이 진정한 가치입니다. 이런 코어객체 사용에서부터 boolean이 바른 의미로 사용되게 유도함으로서 사용자의 코드도 점진적으로 boolean을 가부형에 바르게 쓰도록 유도하는 것입니다.
이는 장기적으로 언어의 표현이 명확하고 타언어를 사용하던 개발자도 손쉽게 의미를 파악할 수 있게 돕게 됩니다.

undefined

undefined는 이 전의 자바스크립트에서는 애매한 부정값으로 사용되는게 현실입니다. es2015에서는 ‘값이 없음’이라는 본연의 뜻을 나타내도록 언어의 여러 요소에서 강제하게 됩니다. 기존 언어부분을 변경할 수는 없으므로 새로운 언어 요소인 펼치기, 해체 등의 기능에는 undefined가 명확하게 값이 없음과 동일하게 사용되도록 하고 있습니다. 마찬가지로 이러한 언어적 강제요소를 통해 사용자의 코드 작성에도 undefined를 값이 없음이라는 의미로 사용하게 유도하게 됩니다.

//해체의 기본값할당은 값이 없을때나 undefined이 들어있을때나 동일하게 발동됨
let [a, b = 3] = [1, undefined];
console.log(b); //3

//함수의 기본값도 마찬가지로 undefined를 보내도 동일하게 작동함.
const test = (a, b = 3)=>a + b;
console.log(test(1, undefined)); //4

이상의 사례에서 살펴본 것처럼 es2015는 보다 기본형에 대한 명확한 사용과 의미부여를 유도하기 위한 다양한 장치를 마련했습니다. 이제 새 시대에는 기본형의 역할에 맞게 사용하는게 바람직하다고 생각합니다 ^^;

암묵적인 시스템의 개선

자바스크립트에는 언어스펙을 외우고 있지 않은 사람이 보면 굉장히 이해하기 어려운 암묵적인 시스템이 많이 들어가 있습니다. 이는 코드상에 표현되어있지 않은 언어스펙이나 엔진구현을 외우고 있다라는 것을 전재로 하기 때문에 굉장히 좋지 않습니다. 누구나 코드를 보고 명확하게 의미를 알 수 있으려면 최대한 이러한 암묵지를 제거하는 것이 좋습니다. 사실 언어에서 완전히 암묵지를 제거할 수는 없습니다. 하지만 문법외적인 식별자나 특정한 키가 등장하는 것은 코드의 이해를 굉장히 어렵게 합니다. 예를들면 자바에는 this, super와 같은 문법 외적인 식별자레벨의 암묵지가 존재합니다(물론 여기서 말하는 문법은 문의 레벨입니다)
자바스크립트에서는 훨씬 많은 암묵지가 들어있고 es2015에서는 이러한 문제를 상당부분 개선하려고 노력했습니다.

arguments

어떤 함수는 호출되면 암묵적으로 그 안에 arguments라는 변수가 존재하고 그 변수에 인자가 리스트 형태로 들어있다고 알고 계실 분들이 많으실겁니다. 하지만 전체 개발자(모든 개발언어를 포함한)를 대상으로 한다면 아는 사람은 매우 적은 편인 것입니다. 이러한 사람들에게 다음의 코드는 어떤 의미를 갖을까요?

const sum = function(){
  return Array.from(arguments).reduce((p, v)=>p + v, 0);
};

전혀 해석할 수 없습니다. arguments가 뭔지 알 수 없기 때문이죠. 언어의 암묵지로 존재하기 때문에 자바스크립트 언어스펙을 외운 사람에게만 알 수 있는 코드가 되어버렸습니다. es2015에 도입된 rest parameter를 이용하면 코드상으로 명확히 표현할 수 있으므로 어떤 언어의 개발자가 봐도 의미를 추론할 수 있게 됩니다.

const sum = function(...element){
  return element.reduce((p, v)=>p + v, 0);
};

이제 누가봐도 sum(1,2,3,4)를 넘기면 10이 나올거라 생각하게 되었습니다. 따라서 개인적인 추천은 es2015상에서는 무조건 arguments를 사용하지 말아야한다는 것입니다.
실제로 화살표함수에서는 arguments객체 자체가 존재하지 않습니다. 언어차원에서도 새로운 요소에서는 암묵지시스템을 제거해가고 있습니다.

Symbol

자바스크립트는 기본형에 해당되지 않는 모든 값은 객체입니다. 이 객체는 형변환이나 JSON변환등에 반응하는 특별한 트리거함수를 갖을 수 있는데 대표적으로 다음과 같은 것들이 있습니다.

let a = {
   toString:_=>'a', //문자열로 형변환시 발동
   valueOf:_=>1, //숫자값으로 형변환시 발동
   toJSON:=>'{a:1}' //JSON.stringify 호출시 발동
};

이는 모두 일반문자열로 그러한 의미를 갖는다는 것을 코드상으로 전혀 파악할 방법이 없습니다. 그저 언어스펙을 외우거나 JSON스펙을 외운 사람에게만 의미가 있습니다. 이 부분도 보다 명확한 의미를 코드상에서 부여할 수 있는 장치가 마련되었는데 바로 심볼입니다. 우선 형변환을 위해 다음과 같은 표현을 도입해보죠.

let a = {
   [Symbol.toPrimitive]:hint=>hint == 'string' ? 'a' : 1
};

우선 객체의 키로 Symbol.toPrimitive가 오기 때문에 명확한 키의 용도를 표현하게 됩니다. 평범한 문자열이나 사용자가 정의한 함수가 아니라 형변환에 사용되는 특수한 키다라는 것을 훨씬 명확하게 표현하고 있습니다.
하지만 toJSON의 경우는 JSON측에서 정의하고 있는 프로토콜이라 어쩔 수 없습니다만, es2015에 새로 도입된 Iterator Protocol에서는 여전히 ‘next’문자열을 키로 사용한 것은 문제점이라고 생각합니다.
심볼에는 다양한 측면과 기능이 있지만 여기서는 명확한 코드의 표현 측면만 살펴보았습니다. 더 자세한 내용은 아래 링크를 참고하세요.

[es6] Symbol #1
[es6for3] Symbol 대체

결론

es2015에 도입된 다양한 기능의 목적 중에 하나인 코드의 명확성 부분을 살펴봤습니다.
다음편에서는 문을 값으로 표현하는 다양한 장치를 차근차근 살펴보도록 하죠.

P.S
아래 링크에서는 rest parameter의 목적이 매우 잘 표현되어있습니다.

“Provide a better arguments so we can deprecate, obsolete, and some years hence burn with fire / salt the earth anything to do with arguments, foo.arguments, etc.”

harmony:rest_parameters