[YOU DON'T KNOW JS] 타입과 값

uoayop·2021년 10월 6일
1

JavaScript

목록 보기
22/24
post-thumbnail

👩🏻‍💼 "자바 스크립트는 동적 언어니까 타입 개념이 없을 거야"

👼🏻 "자바스크립트에도.. 타입이 있어요"

  • ECMAScript 언어 타입 : Undefined, Null, Boolean, String, Number, Object
  • 타입 : 자바 스크립트 엔진, 개발자 모두에게 특정 값들을 구별할 수 있게 해주는 고유한 집합
    • 42 (숫자) != "42" (문자열)

타입

내장 타입

null, undefined, boolean, number, string, object, symbol

  • typeof 연산자로 타입을 알 수 있음

  • null

    • null은 falsy한 유일한 원시값이지만, 타입은 object로 나옴 (황당)
      typeof null === "object"

    • 타입으로 null인지 알기 위해선 조건이 하나 더 필요함

      var a = null;
      (!a && typeof a === "object"); //true

변수와 값

  • 변수엔 따로 타입이 없음

    • 따라서 언제나 어떤 형태의 값이라도 가질 수 있음
  • typeof (변수) = "이 변수에 들어있는 값의 타입이 뭐니?"

  • 즉, 변수는 타입이 없지만 값은 타입이 있고
    타입은 값의 내재된 특성을 정의함

undefined

  • 값이 없는 변수의 값은 undefined

  • 이때 undefined는 값이 없는 것이지 선언은 되어있는 상태를 의미함

    • 접근 가능한 스코프에 변수는 선언되었지만, 값이 할당되어 있지 않은 상태
  • typeof undefined = "undefined"

  • 🔥 안전 가드

    • JS는 선언되지 않은 변수의 타입도 undefined로 반환함

    • 👩🏻‍💼 "머야 헷갈리고 완전 구린 거 아니에요?"
      👼🏻 "오히려 좋아"

    • 선언되지 않은 변수를 체크하는 데에 사용할 수 있음!

      if (선언되지 않은 변수) {
      	console.log("변수가 없어서 에러 발생");
      }
      
      if (typeof 변수 !== "undefined") {
      	console.log("안전하게 존재 여부 확인 가능")
      }
    • 의존성 주입 설계 패턴

      • 특정 변수가 있는지 확인한 후 함수를 구현해야 할 때

        function somethingCool(특정 변수) {
        	var helper = 특정 변수 || 
                function() {
                    // somethingCool에서 제공하는 기본 기능
                };
            
        	var val = helper();
        	// ...
        }
      • 특정 변수가 있으면 그대로 사용하고, 없으면 함수 바디를 정의함

      • 👍🏻 다른 사람이 복붙을 해도 안전하게 특정 변수가 존재하는지 체크 가능함


배열

  • JS 배열은 어떤 타입의 값이라도 담을 수 있는 그릇임!
  • 배열 크기는 미리 정하지 않고 선언할 수 있고, 원하는 값을 추가하면 됨
var a = [];
a.length; // 0

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

a.length; // 3

key-value : 경악

  • (경악 1) 배열 인덱스는 숫자이지만, 배열 자체도 하나의 객체여서 key-value 문자열을 추가할 수 있음
  • (경악 2) 배열 인덱스로 추가할 때만 length가 증가함, 만약 key-value로 추가했다면 length는 증가하지 않음
var a = [];

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

a.length; // 1
a["key"]; // 2
a.key; 	  // 2
  • (경악 3) 키로 넣은 문자열 값이 10진수 숫자로 타입이 바뀌면, 숫자 키를 사용한 것 같은 결과가 초래됨
var a = [];
a["13"] = 42;
a.length; // 14

// 순식간에 0번 ~ 13번 인덱스가 생김

👉🏻 배열에 문자열 타입의 key를 두지말자.
만약 써야한다면 객체를 대응하고, 배열 원소의 인덱스는 반드시 숫자로 쓰기~

유사 배열

  • 유사 배열 : 숫자 인덱스가 가리키는 값들의 집합
// arguments 객체 
function foo() {
	var arr = Array.prototype.slice.call(arguments);
	arr.push("안녕하세요");
	console.log(arr);
	// ["변수1", "변수2", "안녕하세요"]
}

foo("변수1", "변수2");


// ES6 부터 기본 내장 함수 Array.from이 권장됨
var arr = Array.from(arguments);
// 함수의 인자를 리스트로 반환

문자열

  • js의 문자열은 문자 배열과 같지 않음

  • ⭕ 공통점 : length, indexOf (ES5) , concat 사용 가능
    ❌ 차이점 : 문자열불변값이지만, 배열가변값

  • [꿀팁🍕] 문자열을 다룰 때 사용하는 배열 메소드를 빌려쓰는 방법
    • 배열 불변 메소드 Array.prototype.join.call
var a = "어쩔티비"

var b = Array.prototype.join.call(a, "-");
// Array 프로토타입 이용해서 배열 메소드 빌려쓰기

b;
// 어-쩔-티-비
  • [꿀팁🍔] 문자열 뒤집는 방법
    • 문자열엔 reverse 가변 메소드 없음
    • 설상가상 문자열은 불변값이라 배열의 가변 메소드도 통하지 않음
      = 빌려쓰는 것 안됨
    • 문자열 -> 배열 -> 문자열 : 꼼수를 쓰자
var a = "안되나요?"

a.reverse; // undefined

Array.prototype.reverse.call(a);
// "안되나요?"

var c = a.split("").reverse().join("");
// split : a를 문자의 배열로 분할함
// reverse : 문자 배열의 순서를 거꾸로 뒤집음
// join : 문자 배열을 합쳐 다시 문자열로 되돌림

c;
// ?요나되안
  • 문자 배열 -> 문자열 : join("")

숫자

  • 모든 숫자를 number 타입 하나로 퉁침
  • .toFixed(자릿수) : 다음 자릿수에서 해당 자릿수로 반올림
var num = 42.59;

a.toFixed(0); // 1 -> 0 : "43"
a.toFixed(1); // 2 -> 1 : "42.6"
a.toFixed(2); // 3 -> 2 : "42.59" ... 

42.toFixed(3);
// error : 42인지 42.인지 알 수 없음

(42).toFixed(3);
0.42.toFixed(3);
42..toFixed(3);

부동 소수점

  • 아찔..

0.1 + 0.2 === 0.3; 
// false
  • 미세한 '반올림 오차' 를 어떻게 해결하면 좋을까?
    • 머신 입실론 (Machine Epsilon) : 미세한 오차
    • Number.Epsilon 을 이용해 동등함을 비교할 수 있음
function isequal(n1, n2) {
	return Math.abs(n1 - n2) < Number.EPSILON;
}

var a = 0.1 + 0.2;
var b = 0.3;

isequal(a, b); // true

특수 값

  • null 과 undefined

  • null : 예전엔 값이 있었지만, 지금은 없는 상태
    • 화장실에 휴지 걸이는 있지만 휴지가 없다
  • undefined : 값을 아직 가지지 못한 상태
    • 화장실에 휴지 걸이도 없다.
  • void 연산자

    • undefined는 void 연산자로도 얻을 수 있음

    • void ____ 는 어떤 값이든 무효로 만들어, 항상 결괏값을 undefined로 만듦

      • 기존 값은 건드리지 않고 연산 후 값은 복구할 수 없음
    • void 0 == void 1 == undefined

    • 값이 존재해야 하는 곳에서 그 값이 undefined가 되어야 좋을 경우에만 사용하자!

특수문자

  • NaN (Not a Number)
    • 숫자가 아니라는 의미보단 유효하지 않은 숫자 라고 보는 것이 좋다.
var a = 2 / "메롱";	// NaN

typeof a === "number"; // true
  • 난리났다 난리났어..
    어쨌든 (NaN) 의 type은 "number"다.

  • 게다가 NaN은 다른 어떤 NaN과도 동등하지 않음
    NaN !== NaN


👩🏻‍💼 "엥 그럼 NaN인지 여부를 어떻게 판단하죠?"

🤡 "isNaN을 사용하렴.. "

isNaN(a); // false

  • 구라임.
  • 사실 isNaN은 인자 값이 숫자인지 여부를 평가하는 기능이 전부임💦
    단순히 숫자가 아니면 true를 반환하기 때문에 단순 문자열을 넣어도 true가 반환됨.

👼🏻 "Number.isNaN() 를 사용하면 됨"

  • ES6부터 등장한 요 폴리필을 쓰면 안전하게 체크 가능

  • NaN은 세상 모든 언어를 통틀어 "자기 자신과도 동등하지 않은" 유일한 값임!


0

  • JS엔 +0, -0이 존재함

  • -0 ----(문자열화) ----> "0"
    "-0" ----(숫자화) ----> -0

    -0을 문자열화 하면 항상 "0"이 나옴
    (경악 1) 근데 반대로 문자열("-0")에서 숫자로 바꾸면 있는 그대로 보여줌

  • (경악 2) 비교를 할 때도 이와 비슷한 상황이 벌어짐

var a = 0;
var b = 0 / -3; // -0

a == b; // true
-0 == 0; // true

a === b; // true
-0 === 0; // true
  • 왜 이딴 짓을 한걸까?
    • 바로 값의 크기로 어떤 정보와
      그 값의 부호로 또 다른 정보를 동시에 나타내야 하는 경우가 있기 때문!
      • ex) 값의 크기 = 애니메이션 프레임당 넘김 속도 / 값의 부호 = 넘김 방향
    • 잠재적인 정보 소실을 방지하기 위해 0의 부호를 보존함!

Object.is

  • 특이한 값을 비교할 땐 Object.is를 사용하면 좋음
    ex) NaN, -0, 0 등

  • 특이한 값이 아니라면 그냥 ==, ===를 사용하자


값 VS 레퍼런스

  • js에서는 어떤 변수가 다른 변수를 참조할 수 없음

    • js에서 참조는 값을 가리킴
    • 서로 다른 참조 10개가 있다면, 이들은 항상 공유된 단일 값을 개별적으로 참조함

  • 값의 타입 만으로 value-copy(값 복사) 인지, reference-copy(레퍼런스 복사) 인지 결정됨

  • 값 복사
    • 단순값을 복사할 때
    • null, undefined, string, number, boolean
var a = 2;
var b = a;	// 'b'는 'a'에서 값을 복사함

b++;
a; // 2
b; // 3
  • 레퍼런스 복사
    • 객체나 함수를 복사할 때
    • 동일한 공유값에 대해 개별 레퍼런스를 갖게됨!
var c = [1, 2, 3];
var d = c;	// 'd'는 공유된 '[1, 2, 3]' 값의 레퍼런스

d.push(4);
c;	// [1, 2, 3, 4]
d;  // [1, 2, 3, 4]
  • 배열 같은 합성 값값 복사로 전달하려면 사본을 만들어 전달하자
    • var d = c.slice();
    • slice() 는 얕은 복사로 사본을 만듦
profile
slow and steady wins the race 🐢

0개의 댓글