개요
Nullish coalescing operator – 널병합연산자라고 약간 억지스럽게 번역된 연산자입니다.
이 연산자가 하는 일은 좌항이 null 또는 undefined인 경우 우항을 값으로 반환하고 아니면 좌항을 반환하는 거죠.
기존 ||은 falsy에 반응하던 것에 비해 훨씬 좁은 범위인 null, undefined에만 반응하는 연산자입니다. 따라서 좌항이 0, “”, false, Nan 같은 falsy값일지라도 우항으로 넘어가지 않는다라는 장점이 있습니다.
하지만 널리쉬라는 이름과 달리 undefined를 허용함으로서 언어차원에서 undefined의 위상이 좀 달라졌습니다.
es6처음에는 분명히 없다라는 위상을 확실하게 하고 그 외엔 쓰지말라고 언어차원에서 이것저것 밀어줬는데 널리쉬계열에서는 null과 undefined를 동급처리하기 때문에 undefined를 null 대신 쓰게 하는 유도 작용이 일어나 위상이 더 넓어져버렸습니다. 아마 개인적인 생각인데 이건 js의 기본적인 작동의 문제인데 오브젝트의 없는 키 같은 것들이 자바에서는 null로 나오지만 js에서는 undefined로 나오기 때문에 어쩔 수 없는 선택이었을 것입니다.
일반적인 사용법
널병합연산자는 보통 다음과 같은 예로 많이 표현됩니다.
case1( ) ?? case2( )
case1이 성공하면 그 결과가 답이 되고 case1이 null이나 undefined를 반환한다면 case2를 실행하려는 것이죠. 이미 비슷한 연산자가 swift나 kotlin등 최신 언어에는 탑재되어있습니다. 그리고 이 활용도 다른 언어에서는 깊이 연구되어있습니다.
널병합 연산자는 연속된 체인을 허용하기 때문에 일종의 chain of responsibility나 데코레이터처럼 사용할 수 있습니다.
case1( ) ?? case2( ) ?? case3( ) ?? case4( ) ?? error()
이런 식으로 switch나 else if를 대체하는 경우가 흔합니다. 제어문은 판별한 조건이 명시되어있는 것에 비해 위의 체인을 이용하면 런타임에 각 함수의 결과에 따라 진행여부가 판단되기 때문에 훨씬 유연한 조건체인을 만들 수 있는 거죠. 원래 chain of responsibility를 사용하는 장점 그 자체죠.
데코레이터도 간단합니다. 자유변수나 공유하는 인스턴스에 상태를 갱신하면서 결과값으로 null을 반환할거냐 아니냐로 전진을 정하면 되니까 큰 문제없이 진행됩니다.
kotlin의 let을 흉내내기
만약 람다가 관여할 수 있다면 보다 동적으로 널체인을 활용할 수 있을 것입니다. 만약 어떤 람다가 인자로 아무 대상객체를 받아들어 뭔가 반환한다면 이 람다를 이용하여 다음과 같은 let함수를 생각해볼 수 있습니다.
const let = target=>block=>block(target); const f = let({a:3, b:5}); f(it=>it.a); //3 f(it=>it.b); //5
위 예에서 최초 let을 호출할 때 인자로 넘긴 target이 반환될 함수에 바인드 되어 그 이후 람다를 넘기면 그 람다에게 최초의 target을 자동으로 전달해줍니다. 함수형으로는 이렇지만 Object.prototype에 let을 만들면 자연스레 this를 넘겨주면 됩니다.
Object.prototype.let = function(block){ return block(this); }; ({a:3, b:5}).let(it=>it.a); //3
프로토타입을 이용한 위의 예제에서는 보다 자연스럽게 모든 객체의 메소드로서 let을 사용하여 this를 람다의 인자로 제공합니다(화살표함수는 짜피 this를 전달할 수 없으니까요 ^^)
이제 ??연산자를 보다 유연하게 사용할 수 있게 되었습니다.
const target = {a:3, b:5, c:4}; target.let(it=>it.k) ?? target.let(it=>it.h) ?? 10; //10
let을 응용한 ?? 체인에서는 미리 정의한 함수만 체인하지 않고 즉시 넘긴 람다를 이용해 체인을 구성할 수 있습니다.
위 예에서는 최초 target.k를 찾아보고 undefined이므로 target.h를 찾아본 뒤 최종 10이 됩니다.
더 나아가 널리쉬 연산자(?)와 결합하면 더욱 강력해집니다.
target?.let(it=>it.k) ?? target?.let(it=>it.h) ?? 10;
이 경우 target자체가 null인 경우도 자동으로 처리하게 되므로 광범위한 null처리가 굉장히 짧은 구문에서 처리되는 것을 알 수 있습니다.
결론
??와 ?는 한결 편한 문법으로 도처에 도사리고 있는 null문제를 사전에 방지할 수 있게 돕습니다.
기존에 번거롭게 if를 다중으로 전개해 막아야했던 null처리를 보다 쉽게 작성할 수 있는 틀을 제공해주긴 하지만 그렇다고 개발자가 꼼꼼히 체크해야 한다는 점이 변하는 것은 아닙니다.
이 새로운 문법을 이용해 보다 꼼꼼하게 null상황을 통제하죠 ^^
recent comment