제2장 가치
2.첫 번째 행
강력하게 유형이 지정되는 다른 언어와 달리 JavaScript 배열은 문자열, 숫자, 개체 및 기타 배열이나 모든 유형의 값을 담을 수 있는 컨테이너입니다.
먼저 설정하지 않고 배열의 크기를 선언할 수 있습니다.
원하는 값을 추가하기만 하면 됩니다.
var a = ();
a.length; // 0
a(0) = 1;
a(1) = "2";
a(2) = (3);
// a = ( 1, "2", (3))
a.length; // 3JAVASCRIPT
천공 어레이를 취급할 때는 주의하십시오.
var a = ();
a(0) = 1;
a(2) = 3;
a(1); // undefined
a.length; // 3JAVASCRIPT
실행은 되지만 도중에 건너뛰는 빈 슬롯은 혼란을 일으킬 수 있습니다.
슬롯 a(1)의 값이 정의되지 않은 것처럼 보이지만 a(1) = 정의되지 않은 것으로 설정하는 것과는 다릅니다.
배열 인덱스는 숫자이지만 배열 자체는 객체이므로 여기에 키/속성 문자열을 추가할 수 있습니다.
그러나 배열 길이는 증가하지 않습니다.
키로 입력한 문자열 값을 표준 10진수로 변환하면 문자열 키 대신 숫자 키를 사용한 것과 같은 결과가 나오니 주의하세요.
var a = ();
a(0) = 1;
a("foobar") = 2;
a.length; // 1
a("foobar"); // 2
a.foobar; // 2
a("13") = 42;
a.length; // 14
배열에 문자열 유형 키/속성을 넣는 것은 권장되지 않습니다.
이렇게 해야 하는 경우 개체를 교체하고 배열 요소 인덱스가 숫자인지 확인하십시오.
2.1.1 의사 배열
var a = (1, 2, 3);
array; // (1, 2, 3)
var n = document.querySelectorAll('div'); // NodeList (div, div, div, div, ...)
var e = document.body.children; // HTMLCollection (noscript, link, div, script ...)
Array.isArray(a); // true
Array.isArray(n); // false
Array.isArray(e); // falseJAVASCRIPT
위의 예에서 a는 배열이고 n과 e는 의사 배열입니다.
모두 ()로 묶어서 똑같아 보이지만 Array.isArray 메서드를 사용하여 어떤 것이 배열인지 확인할 수 있습니다.
직접 배열 리터럴로 선언된 배열만 배열입니다.
var arr = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
위의 arr 개체는 의사 배열입니다.
키는 숫자이며 길이라는 속성이 있습니다.
배열은 또한 객체의 속성을 사용하는 트릭입니다.
배열과 마찬가지로 arr(0), arr(1), arr(2) 및 arr.length와 같은 것을 사용할 수 있습니다.
배열과 같은 배열에는 배열과 같은 메서드를 사용할 수 없으므로 배열과 같은 배열은 서로 구분해야 합니다.
a.forEach(fucntion(el) { console.log(el); }); // 1, 2, 3
e.forEach(fucntion(el) { console.log(el); }); // Uncaught TypeError: e.forEach is not a fucntion
// 배열 프로토타입에서 forEach 메서드를 빌려와 forEach를 사용
Array.prototype.forEach.call(e, fucntion(el) { console.log(el); });
// ES6 이상 최신 자바스크립트에서 사용법
Array.from(e).forEach(function(el) { conosle.log(el); });
책의 비슷한 배열을 이해하지 못해서 Zerocho의 글을 참고했습니다.
https://www.zerocho.com/category/JavaScript/post/5af6f9e707d77a001bb579d2
2.2 문자열
우리는 종종 문자열을 단순히 문자의 배열로 생각합니다.
JavaScript 문자열은 비슷해 보이지만 문자 배열과 동일하지 않습니다.
var a = "foo";
var b = ("f", "o", "o");
a.length; // 3
b.length; // 3
var c = a.concat("bar"); // "foobar"
var d = b.concat(("b", "a", "r")); // ("f", "o", "o", "b", "a", "r")
a === c; // false
b === d; // false
a; // "foo"
b; // ("f", "o", "o")
문자열은 배열(의사 배열)처럼 보입니다.
그러나 문자열은 변경할 수 없지만(불변 값) 배열은 변경할 수 있습니다(값 변경). 문자열은 변경할 수 없는 값이므로 문자열 메서드는 내용을 즉시 변경하지 않고 항상 새 문자열을 만들고 반환합니다.
문자열의 순서를 뒤집기 위해 reverse를 사용하면 문자열은 불변 값이고 즉시 변경되지 않기 때문에 가변 배열 방법이 작동하지 않습니다.
많은 가능성이 있지만 제시하지는 않겠습니다.
2.3 숫자
숫자는 Javascript의 유일한 숫자 유형이며 정수와 부동 소수점 숫자를 모두 포함합니다.
자바스크립트에 충실합니까? 정수가 없습니다.
부동 소수점과 정수는 모두 숫자입니다.
C 언어를 공부하면서 이진 부동 소수점 숫자가 메모리에 저장되는 방식과 용도에 대해 조금 배웠습니다.
javascript 숫자를 올바르게 사용하는 방법을 이해하기 위해 메모리 비트 패턴을 알고 싶다면 IEEE 754 세부 정보를 읽으십시오.
2.3.1 숫자 구문
// 소수점 앞 정수가 0이면 생략 가능
let a = 0.42;
let b = .42;
// 소수점 이하가 0일 때도 생략 가능
let a = 42.0;
let b = 42.; // 틀린코드는 아니나 좋지 않은 코드
// 아주 크거나 아주 작은 숫자는 지수형으로 표시하며, toExponential() 메서드의 결과값과 같다.
let a = 5E10; // 50000000000 => 5 * 10^10
a.toExpotential(); // "5e+10"
let b = 1/a; // 2e-11
// 숫자 값은 Number 객체 Wrapper로 Boxing할 수 있기 때문에 Number.prototype 메서드로 접근 가능
let a = 42.42;
a.toFixed(0); // 42
a.toFixed(1); // 42.4
a.toFixed(2); // 42.42
a.toFixed(3); // 42.420
a.toFixed(4); // 42.4200
// toPrecision()은 유효숫자 개수를 지정할 수 있다.
let a = 42.42;
a.toPrecision(1); // 4e+1
a.toPrecision(2); // 42
a.toPrecision(3); // 42.4
a.toPrecision(4); // 42.42
2.3.2 작은 십진수 값
0.1 + 0.2 === 0.3; // false
부동 소수점 이진법의 0.1과 0.2는 원래 숫자와 일치하지 않습니다.
0.1 + 0.2는 0.30000000000000004에 가깝습니다.
두 숫자를 비교하려면 Number.EPSILON으로 비교할 수 있습니다.
자세한 내용은 다루지 않겠습니다.
2.3.3 32비트 정수(부호 있음).
정수의 “안전 범위”는 약 9조(53비트)이지만 32비트 숫자로만 가능한 연산이 있기 때문에 실제 범위는 훨씬 작습니다.
따라서 정수의 안전한 범위는 Math.pow(-2.31) 약 -21억에서 Math.pow(2.31) – 1 약 +21억입니다.
2.4 특수 값
각 유형에는 주의해서 사용해야 하는 특수 값이 있습니다.
2.4.1 값이 아닌 값
정의되지 않은 유형의 값은 정의되지 않은 것입니다.
또한 null 유형에는 하나의 null 값만 있습니다.
따라서 이 둘은 항상 같은 유형과 값을 가집니다.
- undefined 및 null은 종종 비어 있는 값과 값이 없는 값을 나타냅니다.
개발자에 따라 다른 의미로 사용될 수 있습니다. - undefined라는 이름의 지역 변수를 만들 수 있지만 이는 매우, 매우, 매우 나쁜 생각입니다.
무효 연산자
undefined는 내장 식별자이고 값은 정의되지 않지만 이 값은 void 연산자를 사용하여 검색할 수도 있습니다.
var a = 42;
console.log(void a, a); // undefined, 42
void 연산자는 식에 반환 값이 없도록 해야 할 때 유용합니다.
2.4.2 특별한 번호
숫자 유형에는 몇 가지 특별한 값이 있습니다.
숫자가 아닌 숫자
수학 연산에서 두 피연산자가 모두 숫자가 아닌 경우 유효한 숫자를 생성할 수 없기 때문에 결과는 NaN(숫자가 아님)입니다.
NaN은 다른 NaN과 비교할 수 없습니다.
자신과 같지도 않습니다.
NaN === 1/"string" // false
NaN 상태는 isNan() 함수로 확인할 수 있습니다.
하지만 치명적인 단점이 하나 있습니다.
let a = 2 / "foo";
let b = "foo";
a; // NaN
b; // "foo"
window.isNaN(a); // true
window.isNaN(b); // true
“foo”는 분명히 숫자가 아니지만 NaN도 아닙니다.
이 버그는 JavaScript가 탄생한 이후 현재까지 존재해 왔습니다.
ES6부터는 이 문제를 해결할 수 있는 방법이 있습니다.
// ES6 이전
if (!
Number.isNaN) {
Number.isNaN = function(n) {
return (
typeof n === "number" && window.isNaN(n)
);
};
}
let a = 2 / "foo";
let b = "foo";
Number.isNaN(a); // true
Number.isNaN(b); // false
2.5 가치 대 참조
다른 언어의 값에 사용되는 구문에 따라 값 복사(value copy) 또는 참조 복사(reference copy) 형태의 할당/이전.
JavaScript 자체에는 포인터 개념이 없으며 참조는 값을 참조합니다.
따라서 10개의 서로 다른 참조가 있는 경우 각각 단일 공통 값을 개별적으로 가리킵니다.
말보다는 예문을 보자
let a = 2;
let b = a; // b는 언제나 a에서 값을 복사한다.
b++;
// a는 2
// b는 3
let c = (1, 2, 3);
let d = c; // d는 공유된 (1,2,3) 값의 레퍼런스다.
d.push(4);
// c 는 (1,2,3,4)
// d 는 (1,2,3,4)
d = (4, 5, 6);
// c 는 (1,2,3,4)
// d 는 (4,5,6)
JavaScript의 기본 값은 항상 값 복사 방법에서 할당/전달됩니다.
개체나 함수와 같은 복합 값은 할당/전송될 때 항상 참조 복사본을 만듭니다.
d = (4,5,6)
배정되더라도 c
(1,2,3,4)는 영향을 받지 않습니다.
그렇다면 다른 언어와 마찬가지로 포인터 개념이 필요한데 자바스크립트에는 포인터가 없다.
함수 인수도 매우 혼란스러운 영역입니다.
function foo(x) {
x.push(4); // x는 (1,2,3)을 가리키는 별도의 레퍼런스
// (1,2,3,4)
x = (4,5,6); // x는 이전의 (1,2,3)을 가리키지 않고 새로운 (4,5,6)을 가리킴
x.push(7);
// (4,5,6,7)
}
let e = (1,2,3); // e는 (1,2,3)을 가리키는 별도의 레퍼런스
foo(e);
// e는 (4,5,6,7)이 아닌 (1,2,3,4)
e를 인수로 전달하면 e의 복사본이 x에 할당됩니다.
x와 e는 모두 동일한 (1,2,3) 값을 가리키는 별도의 참조입니다.
기능 내에서 x=(4,5,6)
를 사용하여 새 값을 할당해도 초기 참조 e가 가리키는 값에는 영향을 주지 않습니다.
참조 x
~처럼 e
가 가리키는 값을 변경할 방법이 없습니다.
하지만 e
그리고 x
둘 다 자신이 가리키는 공통 값의 내용만 변경할 수 있습니다.
즉, 값 사본을 사용할지 참조 사본을 사용할지 임의로 결정할 수 없습니다.
값의 유형을 보고 엔진의 재량에 따라 결정됩니다.
인수없이 slice()
새 배열의 복사본을 만듭니다(얕은 복사본).