Chapter 2: 값
2021.1.24(일)
책: You don't know JS
배열 vs 유사 배열
자바스크립트의 배열
- 어떤 타입의 값이라도 담을 수 있다. 배열 안에 배열도 넣을 수 있다(다차원 배열).
- 배열 크기 미리 선언할 필요 없다.
- 배열 인덱스는 숫자지만, 배열 자체가 하나의 객체이므로 키/프로퍼티 문자열을 추가할 수 있다.
- 이렇게 추가한 경우 length가 늘어나지 않는다.
- key가 숫자일 경우 문자열 키가 아닌 숫자 키(인덱스)를 사용한 것과 같은 효과가 일어난다. 뭔소리냐면
var a = []; a["13"] = 42; a.length; // 14 -> ?
- 배열에 문자열 타입 키/프로퍼티를 두는 것은 피해야 한다. 키를 사용해야 한다면 객체를 대용하고, 배열 원소의 인덱스로는 숫자만 쓰도록 하자
유사 배열
- 직접 배열 리터럴로 선언한 array가 아닌, 숫자 인덱스가 가리키는 값들의 집합을 유사 배열이라고 한다.
- []로 감싸져있지만 배열이 아닌 친구들을 유사 배열이라고 생각하면 된다.
Array.isArray()
메서드를 통해 배열인지 유사 배열인지 구분할 수 있다.- ES6부터는 기본 내장 함수
Array.from()
을 통해 유사 배열을 배열로 변환할 수 있다. call()
또는apply()
를 통해 배열로 변환하지 않고도 배열 메서드를 빌려쓸 수 있다.Array.prototype.forEach.call(nodes, function(el) { console.log(el); }); [].forEach.call(els, function(el) { console.log(el); }); // 출처: https://www.zerocho.com/category/JavaScript/post/5af6f9e707d77a001bb579d2
문자열 vs 문자 배열
- 자바스크립트 문자열은 문자 배열과 다르다.
let a = "foo";
와let b = ["f", "o", "o"];
는 다르다. - 문자열은 불변값이지만 배열은 가변값이다.
- 문자열은 불변값이므로 문자열 메서드는 항상 새로운 문자열을 생성한 후 명령을 수행한 뒤에 반환한다.
- 반면에, 배열 메서드는 그 자리에서 바로 원본을 수정한다.
- 문자열을 다룰 때 유용한 대부분의 배열 메서드는 사실상 문자열에 쓸 수 없지만, 문자열에 대해 불변 배열 메서드를 빌려 쓸 수는 있다.
reverse()
등의 가변 배열 메서드는 빌려쓸 수도 없다. 이럴 때에는 문자열을split()
으로 배열로 분할해준 다음 가변 배열 메서드를 사용하고 다시 합쳐주는 꼼수를 쓰면 된다. 😌let a = "foo"; a.join("-"); // undefined a.map( /* ... */ ) // undefined let c = Array.prototype.join.call(a, "-"); let d = Array.prototype.map.call(a, (v) => { v.toUpperCase() + "."; }).join(""); c; // "f-o-o" d; // "F.O.O"
자바스크립트의 정신나간 숫자 비교
0.1 + 0.2 === 0.3; // false -> ?
이진 부동 소수점으로 나타낸 0.1과 0.2는 원래의 숫자와 일치하지 않는다. 그러니까 0.1과 0.2를 더해도 0.3이 아닌 0.30000000000000004에 가깝게 계산된다. 0.3 !== 0.30000000000000004
이니 false가 맞긴 한데.. 글킨한데.. 이게맞나..
그러면 대체 어떻게 해야 0.1 + 0.2가 0.3과 같다는 결과를 얻을 수 있을까
보통 '반올림 오차'를 허용 공차로 처리하는 방법을 사용한다고 한다. 이렇게 미세한 오차를 '머신 입실론(컴퓨터가 이해할 수 있는 가장 작은 숫자 단위)'라고 하는데, 자바스크립트 숫자의 머신 입실론은 2^-52(Number.EPSILON
으로 정의되어 있음)이다.
그러니.. 0.1 + 0.2와 0.3의 차이가 2^-52 이하힐 때 true
를 반환하도록 하면 된다.
function numbersCloseEnoughToEqual(n1, n2) {
return Math.abs(n1 - n2) < Number.EPSILON;
}
근데 정말 이렇게까지 해야하는 걸까? 왜 다른 부동 소수점을 사용하는 언어들은 관련 이슈가 없을까?(있는데 내가 모르는 것 같다)
JS의 '특별한' 값들
- undefined 타입의 값은 undefined 뿐이고, null 타입의 값은 null 뿐이다.
- 느슨한 모드에서의 전역 스코프에서
undefined
라는 식별자에 값을 할당할 수 있다.
- 느슨한 모드에서의 전역 스코프에서
void
연산자는 뒤에 오는 값을undefined
로 만들어 버린다.- 어떤 표현식의 반환값이 없다는 걸 확실하게 밝혀야 할 때 사용한다.
NaN
: 나 숫자 아니다NaN
은 어떤 다른NaN
과도 같지 않다.NaN !== NaN
이다.- 그러면 해당 변수가 NaN을 담고 있는지 어떻게 아는가...
- 1) 내장 전역 유틸리티 함수
isNaN()
-> X
정말로 '인자 값이 숫자인지 여부만 평가'하므로 해당 변수가 NaN인지는 알 수 없다.window.isNaN("foo");
의 경우에도 true를 뱉는다. - 2)
Number.isNaN()
-> O
안전하게 NaN 여부를 체크할 수 있다.Number.isNaN("foo");
에서 false를 반환한다.
- 1) 내장 전역 유틸리티 함수
DivisionByZeroError
따위 자바스크립트에 없다. 자바스크립트에는Infinity
가 있다.- 무한대 나누기 무한대는
NaN
이다.
- 무한대 나누기 무한대는
- +0도 있고... -0도 있다.
- -0은 왜 존재하는가
- "+0, -0 개념이 없다면 어떤 변숫값이 0에 도달하여 부호가 바뀌는 순간, 그 직전까지 이 변수의 이동 방향은 무엇인지 알 수가 없으므로 부호가 다른 두 0은 유용하다"라고 한다. 잠재적인 정보의 소실을 방지하기 위해 부호를 붙이는 것이다.
- -0은 왜 존재하는가
값-복사, 레퍼런스-복사는 값의 타입에 의해 결정된다
자바스크립트에는 값 또는 레퍼런스의 할당 및 전달을 제어하는 구문 암시(포인터 등)이 전혀 없다. 대신, 값의 타입만으로 값-복사, 레퍼런스-복사 둘 중 한쪽이 결정된다. 값-복사냐 레퍼런스-복사냐를 우리 맘대로 결정할 수 없다. 이 둘을 결정하는 것은 값의 타입이므로, 타입을 잘 정하는 방법밖에 없다.
원시 값은 불변하다는 특성이 있다는 걸 기억해두면 원시 값 할당 및 전달은 값-복사로 실행된다는 걸 기억하기 편할 것 같다. developer.mozilla.org/ko/docs/Glossary/Primitive#javascript
- 값-복사: null, undefined, string, number, boolean, symbol 등의 단순 값(원시 값)
- 레퍼런스-복사: 객체나 함수 등의 합성 값
'Development > Javascript' 카테고리의 다른 글
[2021 겨울 민트하임 스터디] You don't know JS - Chapter 4: 강제변환(1) (2) | 2021.02.07 |
---|---|
[2021 겨울 민트하임 스터디] You don't know JS - Chapter 3: 네이티브 (6) | 2021.02.04 |
[2021 겨울 민트하임 스터디] You don't know JS - Chapter 1: 타입 (0) | 2021.01.24 |