개발/Javascript

[You don't know JS] Part1 - 2장. 값

lanace 2020. 9. 6. 05:36

Ch2. 값

2.1 배열


하나의 배열에 여러 타입의 값을 담을 수 있다.

  • 배열에 delete 연산자...?!

배열을 변태같이 사용하는 방법

case 1: 구멍난 배열

var a = [];

a[0] = 1;
a[2] = [3];

a[1];  // undefined
a.length; // 3

중간 index를 생략하면 length는 건너뛰고 중간은 undefined가 된다.

case 2: 문자열 index

var a = [];

a[0] = 1;
a["footbar"] = 2;

a.length;  // 1
a.["footbar"];  // 2
a.footbar;  // 2

case 3: string 타입 숫자 index

var a = [];
a["13"] = 42;

a.length; // 14

크롬 기준으로 empty * 13 이라고 나오는걸 보니 좀 신기하긴 하다.

map 을 돌려도 저렇게 나온다.

값이 뭐지?

근데.... 굳이 알아야 할까요?

저런건 그냥 쓰지 말자...

해로운 버그다...

유사 배열

진짜 이상한짓 많이 하는듯 한데...

유사 배열이란 아래의 경우가 있다.

var aaa = function (a, b, c) {
    console.log(arguments);
    console.log(typeof arguments);
}

aaa(1, 2, 3);

argument 는 object이지만 동시에 array이기도 하다.

따라서 여기있는 array를 빼올때 indexOf, concat, forEach 등의 내장 함수를 통해 가져온다.

최근엔 Array.from 을 사용하여 유사배열을 배열로 만든다.

이거 왜 쓰는건지 모르겠다... argument는 뭐지?
왜 나오는건지 모르겠넹;;

2.2 문자열


다른 언어에선 문자열은 문자의 배열로 구현되어져있다.

Javascript 에선 많이 비슷하긴 하지만 둘은 서로 다르다.

  • 문자열 index로 접근할때 charAt과 [index] 의 차이점
var a = 'foo';
var b = ['f', 'o', 'o'];

a.length;  // 3
b.length;  // 3

a.concat("bar");  // 'foobar'
a.concat("bar");  // ['f', 'o', 'o', 'b', 'a', 'r']

a;  // 'foo'
b;  // ['f', 'o', 'o']

가장 큰 차이점은 문자열은 immutable이고, 배열은 mutable 이다.

a[1] = "O";
b[1] = "O";

a;  // 'foo'
b;  // ['f', 'O', 'o']

immutable값은 내용을 바로 변경하지 않고, 새로운 문자열을 생성한 후 반환한다.

Immutable에 대해서 좀더 자세히 알아보자.

문자열 reverse 하기

문자열은 배열이 아니기때문에 reverse나 join, map과 같은 함수는 사용할 수 없다.

따라서 다음과 같이 Array에 있는 메서드를 가져다 사용한다.

var c = Array.prototype.join.call(a, '-');
var d = Array.prototype.map.call(a, function (v){
    return v.toUpperCase() + '.';
});

c;  // "f-o-o"
d;  // "F.O.O"

근데 유니코드가 섞여있는 경우 문자열의 join은 불가능하다는데, 왜그런거지?
마티아스 바이넨의 에스레베르를 사용하라고 하던데...ㄷㄷ?

⇒ 유니코드는 2바이트라서...!!

2.3 숫자


javascript 에선 정수와 부동소수점 모두 number 타입 하나로 처리한다.

Number 객체로 박싱할 수 있어서 Number.prototype 메소드에 접근이 가능하다.

부동 소숫점 이슈

모든 숫자를 부동 소숫점을 사용하기 때문에 고질적인 문제가 발생한다.

0.1 + 0.2 === 0.3 // false

0.1 + 0.2 는 0.30000000....4 에 가깝다.

해결 방법은 Number.EPSILON을 사용하는것이다.

function numbersCloseEnoughToEqual(a, b) {
    return Math.abs(a - b) < Number.EPSILON;
}

최대 허용 오차를 사용하여 구분이 가능하다.

안전한 정수 범위

부동 소숫점때문에 Number.MAX_VALUE 보다 작은 수준에서 안정성을 보장한다.

표현한 값과 실제 값이 정확하게 일치한다고 보장되는 범위를 안전한 정수 범위라 한다.

그치만 9000조를 넘기때문에... ㅇㅇ;;

DB id가 64비드 숫자라면 Big Number와 같은 유틸 라이브러리나 문자열로 처리하는게 일반적이다.

정수인지 확인

Number.isInteger() 를 통해서 정수인지 확인이 가능하다.

안전한 정수인지 여부는 Number.isSafeInteger를 활용하면 된다.

32bit?

이건 언제 사용하는지 한번 찾아보자...ㄷㄷ
뭔지 모르겠넹;; 왜왱?

2.4 특수 값


값이 아닌 값

undefined, null

undefined는 키워드지만 값을 삽입할 수 있다?! strict mode 에선 동작하지 않는다.

undefined = 3;
console.log(undefined);  // 3

undefined

...

void 연산자

void는 어떤 값이던 undefined로 만들어버리는 연산자이다.

도대체 왜쓰는지 모르겠다...

<a href="javascrit: void(0)">???</a>

특수 숫자

NaN ⇒ Not a Number

하지만 typeof NaN은 "number"이다.

NaN === NaN // false

나 블리츠크랭크 아니다?!.png

2.5 값 vs 레퍼런스


  • 자바스크립트엔 포인터 개념이 없음
  • 어떤 변수가 다른 변수를 참조할 수 없음
  • 값의 타입에 따라 값-복사 또는 레퍼런스-복사 가 일어난다.

값-복사

  • null
  • undefined
  • string
  • number
  • boolean
  • symbol

레퍼런스-복사

  • object
  • array
  • function
  • 합성 값
  • 기타 나머지...

함수에서의 복사

함수에서도 마찬가지로 값의 타입에 의해 발생된다.

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

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

a;  // [1, 2, 3, 4]

위의 코드에선 배열이기 때문에 레퍼런스-복사가 발생한다.

내장 함수를 통한 Boxing 데이터 넘길때

function foo(x) {
    x = x + 1;
    x;  // 3
}

var a = 2;
var b = new Number(a);

foo(b);
b;  // 2

⇒ 내부의 스칼라 원시 값이 불변이다.

Number + 1 이 이루어질때 Number는 자동으로 unboxing 되어 2 라는 값이 나오고

2 + 1 인 새로운 원시 데이터로 계산되어 값-복사가 이루어진다.

2.6 정리하기