민규의 개발블로그
자바스크립트 값 본문
"You Don't know JS" 를 참고 하여 작성한 글입니다.
자바스크립트의 값 타입과 작동방식 공부 후 정리
구멍 난 배열 아래의 코드에서 a [1]는 undefined가 되지만 명시적으로 a [1] = undefined라 세팅한 것과는 다르다.
배열 인덱스는 숫자인데, 배열 자체도 하나의 객체여서 키/프로퍼티 문자열을 추가할 수 있다.(배열의 length는 증가하지 않는다.)
그런데 키로 넣은 문자열 값이 표준 10진수 숫자로 타입이 바뀌면, 마치 문자열 키가 아닌 숫자 키를 사용한 것 과 같은 결과가 나오는 점을 주의해야 한다!
유사 배열
JS에서는 문법이 자유롭다 보니 배열이 아닌데 배열 인척 하는 것이 있고 이 것을 유사 배열 객체 혹은 유사 배열이라고 부른다.
유사 배열은 배열의 메소드를 바로 사용할 수는 없고 빌려서 쓸 수 있는 방법이 있는데 배열 프로토타입에서
indexOf( ), concat( ), forEach( ) 메서드를 빌려오는 것이다.
ES6부터는 기본 내장 함수 Array.from( ) 으로 가능하다.
문자열
문자열은 불변 값 이지만 배열은 가변 값이다. 따라서 문자열 메서드는 그 내용을 바로 변경하지 않고 항상 새로운 문자열을 생성한 후 반환한다. 반면에 대부분의 배열 메서드는 그 자리에서 곧바로 원소를 수정한다.
그리고 문자열을 다룰 때 유용한 대부분의 메서드는 사실상 문자열에 쓸 수 없지만, 문자열에 대해 불변 배열 메서드를 빌려 쓸 수는 있다.
하지만 배열에 reverse( )라는 가변 메서드는 문자열에서 문자열은 불변 값이라 바로 변경되지 않으므로 빌려 쓰는 것조차 안된다.
문자열을 reverse( ) 처럼 하는 법
문자열을 배열로 바꾸고 원하는 작업을 수행한 후 다시 문자열로 되돌리면 된다.
숫자
자바스크립트의 숫자 타입은 number가 유일하며 정수, 부동 소수점 숫자를 모두 아우른다.
숫자 값은 Number 객체 래퍼로 박싱할 수 있기 때문에 Number.prototype 메서드로 접근할 수도 있다.
따라서 숫자 리터럴에서 바로 접근한 메서드는 굳이 변수를 만들어 할당하지 않아도 된다.
그러나 .이 소수점일 경우엔 프로퍼티 접근자가 아닌 숫자 리터럴의 일부로 해석되므로 . 연산자를 사용할 때는 주의해야 한다.
특수 값
undefined 타입의 값은 undefined 밖에 없고 null 타입도 값은 null 뿐이다. 그래서 이 둘은 타입과 값이 항상 같다.
일부 개발자는 null은 예전에는 값이 있었지만 지금은 없는 상태이고 undefined는 값을 아직 가지지 않은 것이라 한다.
어떻게 정의하여 쓰든지 null은 식별자가 아닌 특별한 키워드이므로 null이라는 변수에 뭔가 할당할 수는 없지만 undefined는 느슨한 모드에서 식별자로 쓸 수는 있다. (절대 추천하지 않음)
또 모드에 상관없이 undefined란 이름을 가진 지역 변수는 생성할 수 있지만 이 또한 쓰지 마라.
void 연산자
표현식 void는 어떤 값이든 무효로 만들어 항상 결괏값을 undefined로 만든다. 기존 값은 건드리지 않고 연산 후 값은 복구할 수 없다. 그렇지만 잘 쓰지 않고 값이 존재하는 곳에서 그 값이 undefined가 되어야 좋을 경우에만 사용하자.
특수 값
숫자에는 NaN(유효하지 않은 숫자), +Infinity,-Infinity, -0 같은 특수 값이 있다.
NaN인지 여부를 확인할 때는 직접 비교는 안되고 isNaN( ) 함수로 확인해야 한다.
그런데 아래와 같은 isNaN( ) 함수의 결함도 있으므로 다음 폴리필을 쓰면 안전하게 NaN 여부를 체크할 수 있다.
NaN은 자기 자신과도 동등하지 않는 독특함을 응용하여 아래와 같이 해결할 수 도있다.
-0 같은 경우에는 잠재적인 정보 소실을 방지하기 위해 0의 부호가 보존된다.
ex) 값의 크기로 어떤 정보와 그 값의 부호로 또 다른 정보를 동시에 나타내야 하는 애플리케이션
값 (Value)과 참조 (Reference)
자바스크립트에서는 값에 의한 전달이 이뤄지는 6가지 타입 null, undefined, string, number, boolean 그리고 ES6의 symbol 같은 단순 값이 있다. (이들을 원시 타입이라고 한다)
또 참조에 의한 전달이 이뤄지는 Array, Function, Object 3가지 데이터 타입이 있다.(Array와 Function은 모두 객체에 속하기도 하다)
어떠한 원시 타입이 변수에 할당되면 그 변수는 원시 타입을 가진 변수라 생각할 수 있다.
a = 10 이란 값을 가지고 있고 이 변수 a를 = 이란 키워드를 사용해 새로운 변수 d에 할당했을 때 d한테 값을 복사하게 된다. 그래서 a와 d 둘 다 10이란 값을 갖고 있지만 이는 분리되어 있다. 그래서 d를 수정해도 a한테는 영향이 없다.
객체로 할당된 변수의 경우 그 값으로 향하는 참조(Reference)를 갖게 되는데 참조는 메모리에서 객체의 위치를 가리키고 있다. (변수는 실제로 값을 가지고 있지 않음)
아래에서 변수 b에 a를 할당하면 둘은 같은 주소를 공유한다. b에 push를 할 때 메모리 속에 a의 위치로 가서
작업을 하게 된다. 따라서 같은 주소를 갖으므로 a와 b 둘 다 수정된다.
참조 재할당
z를 인자로 넘기면 z의 레퍼런스 사본이 x에 할당된다. x와 z는 모두 동일한 [1,2,3] 값을 가리키는 별도의 레퍼런스다.
이제 함수 내부에서 이 레퍼런스를 이용하여 값 자체를 변경한다. (push(4)) 하지만 그 후 x=[4,5,6]으로 새 값을 할당해도 초기 레퍼런스 z가 참조하고 있던 값에는 아무런 영향이 없다. 즉 z 레퍼런스는 여전히 [1,2,3,4] 값을 바라보고 있다.
레퍼런스 x로 z가 가리키고 있는 값을 바꿀 도리는 없다. 다만 z와 x 둘 다 가리키는 공유 값의 내용만 바꿀 수 있다.
(배열 같은) 합성 값을 값-복사에 의해 효과적으로 전달하려면 손수 값의 사본을 만들어 전달한 레퍼런스가 원본을 가리키지 않게 하면 된다.
스칼라 원시 값을 레퍼런스처럼 바뀐 값이 바로바로 반영되도록 넘기려면 원시 값을 다른 합성 값(객체, 배열 등)으로 감싸면 된다.
값-복사냐 레퍼런스-복사냐를 결정하는 유일한 단서는 값의 타입뿐이므로 사용할 값 타입을 잘 정해서 간접적으로 할당/전달 로직에 반영해야 한다.
'Javascript' 카테고리의 다른 글
자바스크립트 문법 (0) | 2020.11.19 |
---|---|
자바스크립트 강제변환-2 (0) | 2020.11.17 |
자바스크립트 강제변환-1 (0) | 2020.11.16 |
자바스크립트 네이티브 (0) | 2020.11.13 |
JavaScript 타입 (0) | 2020.11.11 |