배열, 문자열, 숫자는 모든 프로그램의 가장 기본적인 구성 요소지만 자바스크립트에서는 독특한 특징을 갖고 있어 개발자를 웃게도, 울게도 만든다.
자바스크립트 배열은 어떤 타입의 값이라도 담을 수 있다.
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 객체를 사용하여 인자를 리스트로 가져오는 방법
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
}
숫자 아니! 그보단 유효하지 않은 숫자, 실패한 숫자!
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도 같다고 나와!!
bssunn
프리미티브 값은 boolean, string, symbol, undefined, null, number
언제나 값-복사 방식으로 할당/전달된다.
객체나 함수 등 합성 값은 할당/전달시 반드시 레퍼런스 사본을 생성한다.
함수 인자로 예를 들어보자.
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에서는 값의 타입만으로 값-복사, 레퍼런스-복사 둘 중 한쪽이 결정된다.
bssunn
프리미티브 값은 boolean, string, symbol, undefined, null, number
언제나 값-복사 방식으로 할당/전달된다.
객체나 함수 등 합성 값은 할당/전달시 반드시 레퍼런스 사본을 생성한다.
함수 인자로 예를 들어보자.
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]
내용이 재미따..!
너무 깔끔하게 잘 정리하셨네요, 잘 읽고 갑니다!
다음에 또 올게요 🙋♀️