[자바스크립트 개발자라면 알아야 할 33가지 개념] #12 자바스크립트 비트 연산 실제로 활용하기!

이윤우·2023년 5월 12일
0

JavaScript

목록 보기
30/34
post-thumbnail

자바스크립트에서 비트연산자는 우리에게 이상한 야생의 세계를 소개합니다. (12 & 3) = 0이 되고 (12 & 4) = 4가 되는 세상이죠. 진짜입니다. 콘솔에서 지금 당장 실행해보세요. 때때로 비트 연산자는 우리가 어떻게 해결해야 할지 확신이 없는 문제들을 해결해주는 해결사가 될 수도 있습니다.

오브젝트 안에 있는 4개의 독립적인 true/false 변수들의 존재를 체크하고 저장하는 가장 좋은 방에 대해 논의해보겠습니다. 이 속성들은 foo1부터 foo4라고 불러봅시가. JavaScript(ES6)에서의 표현법은 아마 다음과 같을 것입니다.

const myObject = {
	foo1: false,
  	foo2: true,
  	foo3: false,
  	foo4: true,
};

상당히 직관적입니다. 하지만 우리의 어플리케이션은 이 속성들의 아주 많은 조합을 체크해야 될 필요가 있습니다. 어렵기도 하고, 언젠가는 하나의 추가적인 속성을 더 추가해야 할 수도 있습니다. 이 문제를 해결하기 위해서 두 가지 가장 확실한 옵션이 있습니다.

1) 모든 가능한 모델 오브젝트 만들기, 그리고 필요할 때마다 코드를 비교하기

const hasFoo2andFoo4 = {
  foo1: false,
  foo2: true,
  foo3: false,
  foo4: true
}

const hasFoo3andFoo4 = {
  foo1: false,
  foo2: false,
  foo3: true,
  foo4: true
}

// ... 나머지 경우의 수 ...

// 그 후에
if (isEqual(myObject, hasFoo2andFoo4)) {
  // 오브젝트가 Foo2와 Foo4만 가지고 있는지 알 수 있습니다.
}

보이는 그대로, 이 방법은 구립니다. 비교하기 위해 16개의 모델 오브젝트를 생성해야 할 것입니다. 이러한 작업은 작은 정보를 얻기 위해서 overhead가 너무 크다고 느껴집니다. 게다가, 우리가 나중에 또 다른 속성을 추가한다면, 모델 오브젝트를 두배로 늘려야 할 것입니다. 분명히, 이 방식은 피해야 합니다. 하지만 다른 옵션은 더 나쁠 수도 있죠...

2) 조건 블록 내에서 각각 개별 프로퍼티 체크하기

if (myObject[2] && myObject[4] && !(myObject[1] || myObject[3])) {
	// 우린 오프젝트가 Foo2와 Foo4만 갖고 있다는 것을 알 수 있습니다.
}

이 방법은 정말 생생한 악몽입니다. 클라이언트 사이드 코드에 약 백만개의 문장을 추가해야 할 것입니다. 이 방법은 처음부터 오류가 발생하기 쉬운 방법입니다. 그리고 후에 어떤 속성이 바뀌거나 새로운 속성이 추가됐을 때, 엄청난 작업이 필요할 것입니다. 그래서 우리는 어떻게 해야 할까요?

자바스크립트 내부의 모든 정수들은 2진법으로 표기될 수 있습니다. toString(2)를 호출함으로써 그들이 어떻게 변하는지 보세요.

(1).toString(2); // 1

(2).toString(2); // 10

(3).toString(2); // 11

(4).toString(2); // 100

이제 이론을 알았습니다. 이제 중요한 부분으로 가봅시다. 이 방법에 숨어있는 진짜 트릭은 비트연산은 이 바이너리 문자열들을 직접 다루고 비교할 수 있게 해준다는 것입니다. 바이너리 문자열 오른쪽에 0을 넣어주는 << 비트 연산은 우리의 10진법 정수를 2진법의 규칙에 맞게 증가시킵니다.

비트연산 비교에서 가장 중요한 것은 "&"와 "|"입니다. "&&"와 "||"와 형태가 매우 닮은 것은 의도적인 것입니다. "&"은 비교하는 두 개의 숫자가 교집합임을 표기하는 것입니다. "|"은 합집합을 의미합니다. 1010 & 1001을 하게 되면 1000이 리턴됩니다. 왜냐하면 왼쪽 끝에 있는 1이 유일하게 공통된 1이기 때문입니다. 1010 | 10011011을 반환할 것입니다. 왜냐하면 OR연산은 둘 중 하나만 있어도 값이 성립하기 때문입니다.

예제를 확인해보겠습니다.

const myObject = {
	foo1: false,
  	foo2: true,
  	foo3: false,
  	foo4: true,
}

const HAS_FOO1 = 1;
const HAS_FOO2 = 1 << 1;
const HAS_FOO3 = 1 << 2;
const HAS_FOO4 = 1 << 3;

let myBitNumber = 0

if (myObject['foo1'] === true) {
	myBitNumber = myBitNumber | HAS_FOO1;
}

if (myObject['foo2'] === true) {
	myBitNumber = myBitNumber | HAS_FOO2;
}

if (myObject['foo3'] === true) {
	myBitNumber = myBitNumber | HAS_FOO3;
}

if (myObject['foo4'] === true) {
	myBitNumber = myBitNumber | HAS_FOO4;
}

console.log(myBitNumber.toString(2)); // 1010

이제 테스트 해봅시다. 속성에 대해 비트연산 숫자를 체크하고 있다면, 체크할 수 있는 4가지가 있습니다. 우리의 숫자가 하나의 명확한 속성을 가지고 있든 아니든, 어떤 주어진 속성의 배열을 가지고 있든 아니든, 명시된 속성들만 가지고 있든 아니든 혹은 속성의 배열을 전부 가지고 있든 아니든말입니다.

0개의 댓글