WTFJS 해설 - 5

undefcat·2021년 4월 18일
0

WTFJS

목록 보기
5/8
post-thumbnail

WTFJS - 5

지난 포스팅에 이어서 계속 정리해보도록 하겠습니다.

Examples

Labels

foo: {
  console.log('first');
  break foo;
  console.log('second');
}
// > first
// -> undefined

💡 해설

자바스크립트에는 label statement가 존재합니다. 일반적인 경우 많이 사용되지 않지만, 중첩 루프문에서 가장 바깥 루프문을 벗어 나야 되는 경우 등 특정 상황에서는 매우 유용하게 사용될 수 있습니다.

예를 들어, 2차원 배열 table[y][x]에서 특정 값을 찾고, 그 값의 y x값을 얻어야 하는 경우 중첩 for문을 돌릴 수 있습니다. label을 모르고 있는 경우

let y = -1
let x = -1

let isFound = false

for (let yi = 0; yi < table.length; yi++) {
  for (let xi = 0; xi < table[yi].length; xi++) {
    if (table[yi][xi] === target) {
      isFound = true
      y = yi
      x = xi
      
      break
    }
  }
  
  if (isFound) {
    break
  }
}

위와 같이 isFound 플래그 변수를 이용해 바깥 루프를 탈출해야 합니다. 하지만 label이 있다는 것을 알고있다면

outer:
for (let yi = 0; yi < table.length; yi++) {
  for (let xi = 0; xi < table[yi].length; xi++) {
    if (table[yi][xi] === target) {
      y = yi
      x = xi
      break outer
    }
  }
}

위와 같이 코드를 짧게 줄일 수 있습니다.

예제 코드의 경우, foo: { ... } 에서 { }는 코드 블록이고, 이 블록에 label을 붙인 경우입니다.

자세한 내용은 label statement문서에서 확인하시기 바랍니다.

Nested labels

a: b: c: d: e: f: g: 1, 2, 3, 4, 5; // -> 5

💡 해설

label statement는 중첩될 수 있으며, 단지 comma operator와 함께 사용되었을 뿐입니다. comma operator는 맨 마지막 expression이 평가되는 operator입니다.

Insidious try..catch

(() => {
  try {
    return 2;
  } finally {
    return 3;
  }
})(); // -> 3

💡 해설

try..catch..finally에서 finally 블록은 try 혹은 catch가 종료되기 전 무조건 실행되는 블록입니다. 따라서, tryreturn 2try 구문이 종료되기 직전에 finally 블록이 실행됩니다. 그런데 finally에서 return을 하였으므로, tryreturn은 무시됩니다.

사실 이 예제보다 더 좋은 예제는 아래와 같은 예제인 것 같습니다.

let num = 0;

(() => {
  try {
    return num++;
  } finally {
    return num;
  }
})(); // -> 1

return으로 함수가 종료되기 전, try의 return statement의 expression은 이미 평가가 됨을 숙지해야합니다.

Is this multiple inheritance?

new class F extends (String, Array) {}(); // -> F []

💡 해설

comma operator는 위에서도 언급했듯, 맨 마지막 expression으로 평가되는 operator입니다. 따라서 위 코드는 new class F extends Array {}(); 로 해석되는 코드입니다.

A generator which yields itself

이 예제는 제 수준이 부족해서 그런지 잘 모르겠지만, 신기한 이유를 도저히 못 찾아서 넘어가겠습니다.

원문의 코드도 오류가 있고, generator가 그저 generator를 리턴하는 것에 불과한데 소개되어 있는 이유를 잘 모르겠습니다.

A class of class

typeof new class {
  class() {}
}(); // -> 'object'

💡 해설

이 예제도 왜 소개되어 있는 걸까요? 그저 익명 클래스를 바로 new 키워드로 instantiate 한 평범한 예제입니다. 물론 메서드의 이름이 class인데, 프로퍼티로 키워드를 허용하기 때문에 문제 되지 않습니다.

물론 타당한 이유가 없다면 자바스크립트의 키워드를 프로퍼티 이름으로 지정하는 것은 좋은 코드는 아닌 것 같습니다.

Non-coercible objects

function nonCoercible(val) {
  if (val == null) {
    throw TypeError("nonCoercible should not be called with null or undefined");
  }

  const res = Object(val);

  res[Symbol.toPrimitive] = () => {
    throw TypeError("Trying to coerce non-coercible object");
  };

  return res;
}
// objects
const foo = nonCoercible({ foo: "foo" });

foo * 10; // -> TypeError: Trying to coerce non-coercible object
foo + "evil"; // -> TypeError: Trying to coerce non-coercible object

// strings
const bar = nonCoercible("bar");

bar + "1"; // -> TypeError: Trying to coerce non-coercible object
bar.toString() + 1; // -> bar1
bar === "bar"; // -> false
bar.toString() === "bar"; // -> true
bar == "bar"; // -> TypeError: Trying to coerce non-coercible object

// numbers
const baz = nonCoercible(1);

baz == 1; // -> TypeError: Trying to coerce non-coercible object
baz === 1; // -> false
baz.valueOf() === 1; // -> true

💡 해설

자바스크립트에서는 암시적으로 타입의 변환이 일어나는 경우가 많습니다. 예를 들어, 비교 및 산술 연산자에 타입이 다른 값들을 피연산자로 사용한다던가, 조건문 등 boolean context가 필요한 부분에 boolean이 아닌 값이 사용되는 경우 등을 얘기할 수 있습니다. WTFJS의 많은 섹션들도 이 내용에 관하여 다루고 있구요.

위 예제에 소개되어 있는 nonCoercible 함수는 이런 일을 막아주는 역할을 하는 유틸함수라고 볼 수 있습니다.

이 함수를 이해하려면 Symbol.toPrimitive를 이해하면 됩니다. nonCoericible 함수 정의 밑에 예제는 지금까지 계속 알아 보았던 타입변환규칙에 따라 암시적으로 타입변환이 일어나 에러가 발생하는 상황들이므로, 따로 알아보진 않겠습니다.

Symbol.toPrimitive문서를 보시면 알 수 있겠지만, 어떤 객체의 값이 다른 값으로 변할 때 호출되는 메서드입니다. toString이 어떤 객체의 값이 문자열로 변환되어야 할 때 호출되는 것과 같은 맥락으로 생각하시면 됩니다.

이 메서드는 매개변수로 hint 문자열을 받는데, 이는 어떤 값으로 바뀌는지 정보가 들어있습니다. 경우에 따라 'number', 'string', 'default' 세 가지의 값 중 하나가 매개변수로 전달됩니다.

어쨌든, 예제에서는 이 메서드가 호출되는 경우 throw함으로써, 타입 변환시 오류를 발생시켜 변환이 되지 않도록 막는 것입니다.

5편을 마치며

이제 1/3 정도 남은 것 같습니다. 오늘 알아본 내용들은 이전 섹션들에 비해 신기한것들이 많이 있지는 않았던 것 같습니다.

그럼, 다음에 또 뵙도록 하겠습니다.

profile
undefined cat

0개의 댓글