WTFJS 해설 - 7

undefcat·2021년 4월 20일
0

WTFJS

목록 보기
7/8
post-thumbnail

WTFJS - 7

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

Examples

Number.toFixed() display different numbers

(0.7875).toFixed(3);
// Firefox: -> 0.787
// Chrome: -> 0.787
// IE11: -> 0.788
(0.7876).toFixed(3);
// Firefox: -> 0.788
// Chrome: -> 0.788
// IE11: -> 0.788

💡 해설

언뜻 보기에는 IE 브라우저가 좀 더 정확해 보입니다. 하지만 사실 Firefox와 Chrome이 부동 소수점 표준을 더 잘 지켜서 나온 결과 입니다.

// Confirm the odd result of rounding a 5 down
(0.7875).toFixed(3); // -> 0.787
// It looks like it's just a 5 when you expand to the
// limits of 64-bit (double-precision) float accuracy
(0.7875).toFixed(14); // -> 0.78750000000000
// But what if you go beyond the limit?
(0.7875).toFixed(20); // -> 0.78749999999999997780

위의 코드에서 볼 수 있듯이, 사실 0.787은 정확히 0.787을 가리키지 않습니다. 컴퓨터에서 소수를 사용할 땐 항상 조심해야 합니다.

Math.max() less than Math.min()

Math.min(1, 4, 7, 2); // -> 1
Math.max(1, 4, 7, 2); // -> 7
Math.min(); // -> Infinity
Math.max(); // -> -Infinity
Math.min() > Math.max(); // -> true

💡 해설

언뜻 보면 이상하지만, 조금만 생각해보면 납득할 수 있습니다.

주어진 값들 중에서 가장 작은 값을 찾고자 한다면, 최초 비교되는 값은 가장 큰 값이어야 할 것입니다. 반대로 주어진 값들 중에서 가장 큰 값을 찾고자 한다면, 최초 비교되는 값은 가장 작은 값이어야 할 것입니다.

명세 역시 이러한 논리에 따라, 어떤 매개변수도 주어지지 않은 경우 최초 비교되는 값을 리턴하도록 정의하고 있습니다.

Comparing null to 0

null == 0; // -> false
null > 0; // -> false
null >= 0; // -> true

💡 해설

일반적으로 이종 타입간 비교의 경우, 숫자로 변환한다고 했습니다. null0이기 때문에, 언뜻 보면 null == 00 == 0으로 계산될 것 같습니다. 하지만 이전 포스팅에서 알아보았던 섹션인 null is falsy but not false 내용에서 abstract equality comparison의 경우, nullundefined에 대해서는 약간 다르게 적용됨을 알아보았습니다.

다시 알아보자면, nullundefined를 비교할 때에는 아래의 3단계를 생각하면 됩니다.

  • 두 피연산자가 같은 null 혹은 undefinded라면 true입니다. (명세 1번 항목)
  • nullundefined를 서로 비교하는 경우 true입니다. (명세 2, 3번 항목)
  • 그 외에는 false입니다. (명세 13번 항목)

즉, null 또는 undefined가 들어가는 비교에서 같은 타입끼리 비교하거나, 혹은 서로를 비교하는 경우를 제외하면 모두 false입니다.

Same variable redeclaration

a;
a;
// This is also valid
a, a;

// Works also in strict mode
var a, a, a;
var a;
var a;

💡 해설

ES6부터는 let 혹은 const같은 block scoping 변수는 재선언시 오류를 내뿜지만, var는 재선언이 가능합니다.

변수 선언을 var let const 키워드로 하지 않으면 암묵적으로 전역객체의 프로퍼티로 해당 변수를 할당하게 되며, 이 경우 전역변수가 되는 효과가 있습니다. 이는 일반적으로 좋은 코드라고 보기 어렵습니다. 따라서, 항상 변수 선언 키워드와 함께 변수를 선언하는 것이 좋습니다.

Default behavior Array.prototype.sort()

[10, 1, 3].sort(); // -> [ 1, 10, 3 ]

💡 해설

sort의 기본 동작은 배열의 요소들을 문자열로 변경한 뒤 비교하므로, 위와 같은 결과가 나오게 됩니다. 따라서 숫자들을 정렬하고자 한다면 비교함수를 넘겨줘야 합니다.

[10, 1, 3].sort((a, b) => a - b); // -> [1, 3, 10]

resolve() won't return Promise instance

const theObject = {
  a: 7
};
const thePromise = new Promise((resolve, reject) => {
  resolve(theObject);
}); // Promise instance object

thePromise.then(value => {
  console.log(value === theObject); // > true
  console.log(value); // > { a: 7 }
});
const theObject = new Promise((resolve, reject) => {
  resolve(7);
}); // Promise instance object
const thePromise = new Promise((resolve, reject) => {
  resolve(theObject);
}); // Promise instance object

thePromise.then(value => {
  console.log(value === theObject); // > false
  console.log(value); // > 7
});

💡 해설

Promise에서 Promiseresolve하면, Promise 값 자체가 resolve되는 것이 아닌, resolvePromiseresolve됩니다.

즉, 평탄화(flatten)됩니다.

WTFJS 페이지에서는 이를 조금 특이한 현상으로 보는데, 사견으로는 오히려 더 합리적이라고 생각합니다. 예를 들어, 보통 순서가 있는 작업을 처리하는 경우

const someThingWork = new Promise((resolve, reject) => {
  // ...
});

someThingWork
	.then(value => {
  		// ...
  		return otherWork; // Promise
	})
	.then(value => { // otherWork가 resolve된 값
  		// ...
  		return anotherWork; // Promise
	})

위와 같이 좀 더 깔끔하게 코드를 작성할 수 있으며, 애초에 어차피 resolve reject하고 이를 then catch로 잡는 것이 일반적이므로 버그를 덜 유발할 수 있다고 생각합니다.

{}{} is undefined

{}{}; // -> undefined
{}{}{}; // -> undefined
{}{}{}{}; // -> undefined
{foo: 'bar'}{}; // -> 'bar'
{}{foo: 'bar'}; // -> 'bar'
{}{foo: 'bar'}{}; // -> 'bar'
{a: 'b'}{c:' d'}{}; // -> 'd'
{a: 'b', c: 'd'}{}; // > SyntaxError: Unexpected token ':'
({}{}); // > SyntaxError: Unexpected token '{'

💡 해설

이전에 계속 알아봤던 내용입니다.

  • {}는 코드 블럭 혹은 객체 리터럴 둘 중 하나로 인식됩니다.
  • 자바스크립트에는 label statement가 존재합니다.

이 두 내용을 안다면 결과를 가지고 충분히 유추할 수 있을 것입니다.

min is greater than max

이 섹션은 Math.max() less than Math.min() 섹션과 중복되는 내용입니다. 넘어가도록 하겠습니다.

7편을 마치며

드디어 다음 포스팅이 마지막이 될 것 같습니다. 다음에 포스팅에서 뵙겠습니다.

profile
undefined cat

0개의 댓글