YOU DON'T KNOW JS 2장

박정훈·2022년 9월 5일
1

YOU DON'T KNOW JS

목록 보기
2/6
post-thumbnail

배열, 문자열, 숫자는 모든 프로그램의 가장 기본적인 구성 요소지만 자바스크립트에서는 독특한 특징을 갖고 있어 개발자를 웃게도, 울게도 만든다.

✨배열

자바스크립트 배열은 어떤 타입의 값이라도 담을 수 있다.

var a = []
a[0] = 1
a[1] = "2"
a[2] = [3]
console.log(a.length) // 3

🤥배열도 하나의 객체였어..!

배열 인덱스는 숫자인데, 배열 자체도 하나의 객체여서 키/프로퍼티 문자열을 추가할 수 있다. 하지만 배열 length가 증가하지는 않는다...!

const b = [];
b[0] = 1;
b["foo"] = 2;
console.log(b.length) // 1이다! 세상에!
console.log(b["foo"]) // 2
console.log(b.foo) // 2

문자열 값이 표준 10진수 숫자로 타입이 바뀌면, 마치 숫자 키를 사용한 것 같은 결과가 초래된다. 주의하자! 배열 원소의 인덱스는 숫자만 쓰자.

var a = [];
a["13"] = 42;
console.log(a.length) // 14 🤨

🙈유사 배열

유사 배열을 진짜 배열로 바꾸고 싶다면 indexOf(), concat(), forEach()등으로 사용하여 해결하는 것이 일반적이다.

arguments

함수에서 arguments 객체를 사용하여 인자를 리스트로 가져오는 방법

function foo() {
    const arr = Array.from( arguments );
    arr.push("bam")
    console.log(arr)
}
console.log(foo("bar", "baz")); // ['bar', 'baz', 'bam']

📔 문자열

흔히 문자열은 단지 문자의 배열이라고 생각한다. 그렇지만 문자열은 실제로 생김새만 비슷할 뿐 문자 배열과 같지 않다!

💪문자열은 불변이었어..!

반대로 배열은 가변 값이다. 불변이기에 그 내용을 바로 변경하지 않고 항상 새로운 문자열을 생성한 후 반환한다.

🤸‍♀️문자열 뒤집어버려

배열에는 reverse()라는 가변 메서드가 존재한다.

const s = [1, 2, 3]
console.log(s.reverse()) // [3, 2, 1]

근데 문자열은 그런거 없다..😢 불변 값이니까! 그럼 어떻게 해야할까?

🙆‍♂️문자열 -> 배열 -> 문자열

책에서는 이를 꼼수라고 한다.

const malza = "malza".split("").reverse().join("")
console.log(malza) //  azlam

주의!! 복잡한 문자(특수 문자, 멀티바이트)가 섞여 있는 경우 이 방법은 통하지 않는다.

숫자

JS의 숫자 타입은 number가 유일! 정수, 부동 소수점 숫자를 모두 아우른다. JS의 정수는... 부동 소수점 값이 없는 값이다.

console.log(42.0 === 42) // true
console.log(typeof 43) // number
console.log(typeof 43.01) // number

🧐작은 소수값

작은거 보기전에 살짝 큰거 어떻게 표현하는지 보고 가자.

const thousand = 1E3

진수 표현은?

console.log(0o363) // 243의 8진수
console.log(0b11110011) // 243의 2진수
console.log(0x100) // 256의 16진수

다시 돌아와서 다음을 보자. 아주 유명한 이진 부동 소수점의 문제점은 JS에서도 나타난다.(IEEE 754 표준)

0.1 + 0.2 === 0.3 // false

이러한 값은 어떻게 비교하는게 좋을까? 일반적으로는 반올림 오차를 허용 공차로 처리하는 방법이 있다. 이렇게 미세한 오차를 머신 입실론이라고 한다. 자바스크립트 숫자의 머신 입실론은 2^-52이다. ES6부터는 EPSILON이 미리 정의되어 있다.

Number.EPSILON = Math.pow(2, -52)

function func(n1, n2) {
  return Math.abs(n1 - n2) < Number.EPSILON;
}

🤔너 정수야?

역시 ES6부터는

Number.isInteger(42) // true
Number.isInteger(42.000) // true
Number.isInteger(42.3) // false

isInteger의 폴리필은!

Number.isInteger = function (num) {
  return typeof num == "number" && num % 1 == 0
}

🙅‍♂️NaN

숫자 아니! 그보단 유효하지 않은 숫자, 실패한 숫자!

console.log(typeof NaN) // number라고?

const a = 10 / "malza";
a === NaN // false

NaN은 NaN과도 동등하지 않다. 자기 자신과도 다르다. NaN인지 여부는 isNaN으로 확인한다.

isNaN("foo") // true

근데 "foo"가 숫자가 아닌건 맞는데... 그렇다고 NaN도 아니다...!👿👿👿 이 버그는 자그마치 자바스크립트 탄생 이후 고쳐지질 않았다.
이는 ES6부터 Number.isNaN()으로 해결 할 수 있다.

Number.isNaN("foo") // false

❗독특한 동등 비교

역시!!! ES6부터 잡다한 예외 걱정 없이 사용할 수 있는, 동등한지 여부를 파악해주는 유틸리티를 지원한다.

Object.is(NaN,NaN) // true. 이제 NaN도 같다고 나와!!

값 vs 레퍼런스

JS에서 값

bssunn
프리미티브 값은 boolean, string, symbol, undefined, null, number
언제나 값-복사 방식으로 할당/전달된다.

JS에서 레퍼런스

객체나 함수 등 합성 값은 할당/전달시 반드시 레퍼런스 사본을 생성한다.
함수 인자로 예를 들어보자.

function foo(x) {
  x.push(4)
  x; // [1,2,3,4]
  
  x = [4, 5, 6]
  x.push(7)
  x // [4,5,6,7]
}

var a = [1,2,3]
foo(a)
a // [1,2,3,4]

a를 인자로 넘기면 a의 레퍼런스 사본이 x에 할당된다. x와 a는 모두 동일한 [1,2,3] 값을 가리키는 별도의 레퍼런스다.

값-복사냐 레퍼런스-복사냐를 우리 마음대로 결정할 수 없음을 기억하자. 전적으로 값의 타입을 보고 엔진의 재량으로 결정된다!

문제!

값과 참조에 대해서 설명해주세요.
js에서는 값의 타입만으로 값-복사, 레퍼런스-복사 둘 중 한쪽이 결정된다.

JS에서 값

bssunn
프리미티브 값은 boolean, string, symbol, undefined, null, number
언제나 값-복사 방식으로 할당/전달된다.

JS에서 레퍼런스

객체나 함수 등 합성 값은 할당/전달시 반드시 레퍼런스 사본을 생성한다.
함수 인자로 예를 들어보자.

function foo(x) {
  x.push(4)
  x; // [1,2,3,4]
  
  x = [4, 5, 6]
  x.push(7)
  x // [4,5,6,7]
}

var a = [1,2,3]
foo(a)
a // [1,2,3,4]
function test(x) {
    x.push("🌭")
    console.log(x) // ['🍕', '🍔', '🍟', '🌭']

    x.length = 0
    x.push("🍿", "🧂", "🥓", "🥚")
  
    console.log(x) // ['🍿', '🧂', '🥓', '🥚']
}

const arr = ["🍕", "🍔", "🍟"]
test(arr) // 바뀌었다! ['🍿', '🧂', '🥓', '🥚']

배열이 나와서 말인데...

정렬 해 보자

let numbers = [5, 17, 2401, 100, 542, 9];
console.log(numbers.sort()); // [100, 17, 2401, 5, 542, 9]

정렬할 때 요소들을 문자열로 취급하기 때문이다! 10의 자릿수를 기준으로 정렬 된 것이다.
값을 제대로 정렬하기 위한 함수를 인자로 넣어줘야 한다.
어떻게?

console.log(numbers.sort((a, b) => a - b));
// [5, 9, 17, 100, 542, 2401]

뒤집어 보자

const array = [1, 2, 3, 4, 5];
const result = array.reverse();
console.log(result);
console.log(array); // 기존 배열도 뒤집힘
// [5, 4, 3, 2, 1]

내용이 재미따..!

profile
그냥 개인적으로 공부한 글들에 불과

1개의 댓글

comment-user-thumbnail
2022년 9월 5일

너무 깔끔하게 잘 정리하셨네요, 잘 읽고 갑니다!
다음에 또 올게요 🙋‍♀️

답글 달기