- 값
배열, 문자열, 숫자는 자바스크립트에서 독특한 특성을 갖고 있어 정확하게 사용하도록 이해해야 한다.
1.1 배열
자바스크립트 배열은 다른 언어와 달리 문자열, 숫자, 객체, 심지어 다른 배열이나 어떤 타입의 값이라도 담을 수 있다.
var data = [1, "2", [3]];
data.length; //3
data[0]; //1
data[2][0]; //3
배열 크기를 미리 정하지 않아도 선언할 수 있고, 그저 원하는 값을 추가하면 된다.
var test = [];
test.length; //0
test[0] = 1; //1
test[1] = "2"; //"2"
test[2] = [3] //[3]
test.length; //3
주의점1. 배열에 키/프로퍼티 문자열을 추가할수는 있으나 length가 증가하지는 않는다.
var test = [];
test[0] = 1; //1
test["second"] = 2;
test.length; //1 (2일것 같지만 1)
주의점 2. 키로 넣은 문자열 값이 10진수 숫자로 타입이 바뀌면, 숫자를 사용한 것 같은 결과가 나온다.
var test = [];
test["13"] = 42; //42
test.length //14
1.2 문자열
자바스크립트 문자열(string)과 문자의 배열은 다르다. 문자열은 배열과 겉모습은 닮았다.
둘다 아래와 같이 length 프로퍼티, indexof() concat() 메서드를 가진다.
var a = "cake";
var b = ["c","a","k","e"];
a.length; //4
b.length; //4
a.indexOf("a"); //알파벳 a의 위치 1
b.indexOf("a"); //알파벳 a의 위치 1
var c = a.concat("walk"); // "cakewalk"
var d = b.concat(["w","a","l","k"]); // ["c", "a", "k", "e", "w", "a", "l", "k"]
a === c // false
b === d // false
그러나 문자열은 불변값, 배열은 가변값이다.
아래처럼, 문자열의 경우 불변값이므로 그 내용을 바로 변경하지 않고 새로운 문자열을 생성한 후 반환하므로
cake, CAKE 두 문자열이 생성된다. 배열은 가변값이므로 cake에 !가 추가되어 cake!가 된다.
// a는 문자열
z = a.toUpperCase(); //"CAKE"
a; //"cake"
a === c; //false
// b는 배열
b.push("!");
b; // ["c", "a", "k", "e", "!"]
1.3 숫자
자바스크립트의 숫자타입은 number가 유일하다. 그러므로 정수, 소수점 숫자까지 모두 아우르는 셈이다.
정수는 소수점 값이 없는 값으로, 42.0은 정수 42와 같다. 언젠가는 개선될 날이 올 것이다.
우리가 보통 알듯이, 정수는 var a = 10; 소수점은 var a = 10.3 이런 식으로 표기한다.
1.3.1 소수값 내기
그리고 숫자 값은 Number 객체래퍼로 박싱이 가능해서 Number.prototype에 있는
toFixed 함수를 사용하여 지정된 소수점 이하자릿수까지 나타낼 수도 있다.
var a = 10.59;
a.toFixed(0); //"11"
a.toFixed(1); //"10.6"
a.toFixed(2); //"10.59"
a.toFixed(3); //"10.590"
다음코드는 false를 반환한다. 이진 부동 소수점으로 나타낸 0.1+0.2는 0.30000~을 반환하기 때문이다.
함수를 쓰던지 다른 비교방법을 써야한다.
0.1 + 0.2 == 0.3 //false
1.3.2 정수값 확인하기
해당 함수는 어떤 값의 정수 여부를 확인한다. (ES6 버젼)
Number.isInteger(42); //true
Number.isInteger(42.000); //true
Number.isInteger(42.3); //false
1.3.3 void 연산자
var a = 10;
console.log(void a, a); // undefined 10
void는 undefined의 내장 식별자로, 값은 undefined하지만 이 값은 void로도 얻을 수 있다.
즉 표현식 void는 어떤 값이든 무효로 만들어서 항상 결과값을 undefined로 만드는 특징이 있다.
극히 제한적으로 쓰이나, void 연산자는 값이 존재하는 곳의 값을 undefined로 만들어야만할 때 쓰면 된다.
1.3.4 NaN에 대한 진실
var a = 2 / "cake";
typeof a; //"number"
이 결과값을 웃기다고 생각할수도 있다. NaN은 '숫자 아님'의 의미가 아닌가?
숫자를 문자열로 나눴는데 타입이 number라고? NaN을 '숫자 아님'이 아니라 '실패한 숫자'라고 기억하면 이해가 된다.
즉, NaN은 경계 값의 일종으로 숫자 집합내에서 특별한 종류의 에러 상황을 나타낸다.
재미있는 사실은 NaN은 너무 귀하신 몸이라 다른 어떤 NaN과도 동등하지 않아서 위처럼 false가 나온다.
isNaN(a);을 사용해야 올바르게 나오는 것 같다. 하지만 이 수식도 문제가 있다.
// NaN의 틀린 비교
a == NaN // false
a === NaN // false
// NaN의 옳은 비교..? 아니다.
isNaN(a); // true
// isNaN()의 치명적 결함
var a = 2 / "cake";
var b = "cake";
isNaN(a); //true
isNaN(b); //true
실패한 숫자가 true라니? 그렇다. isNaN()은 인자값이 숫자인지 여부만 판단해서 2 / "cake"를 숫자로 인식했다.
if(!Number.isNaN) {
Number.isNaN = function(n) {
return (
typeof n === "number" &&
window.isNaN(n)
);
};
}
var a = 2 / "cake";
var b = "cake";
Number.isNaN(a); // true
Number.isNaN(b); // false
ES6부터 등장한 Number.isNaN()을 통해 인자값이 숫자인지 확실히 알수있다.
1.4 값 vs 레퍼런스
다른 언어에서 값은 구문에 따라 값-복사, 레퍼런스-복사의 형태로 할당/전달된다.
자바스크립트의 경우 포인터라는 개념 자체가 없고 참조하는 방법은 조금 다르다. 그리고 어떤 변수가 다른 변수를 참조할 수 없다. 값의 타입만으로 값-복사, 레퍼런스-복사 중 하나가 결정된다. 다음을 보자.
var a = 2;
var b = a; // b는 언제나 a에서 값을 복사한다.
b++;
a; //2
b; //3
// a에 2가 할당되고, b가 a를 가리키는 것이 아니라 값을 복사한다.
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]
// c에 [1,2,3]이 할당되고, d는 c를 가리킨다.
var c = [1,2,3];
var d = c;
d = [4, 5, 6]; // d에 새로운 값이 할당
c; // [1, 2, 3]
d; // [4, 5, 6];
null, undefinde, string, number, boolean, symbol처럼 원시값이라고 부르는 단순 값은 언제나 값-복사 방식으로 할당, 전달된다. 그러나 객체나 함수 등 합성 값은 할당/전달시 반드시 레퍼런스 사본을 생성한다. 중요한 것은 c,d가 [1,2,3]을 소유하는 게 아니라 이 값을 동등하게 참조한다는 점이다. 세번째 예제에서 d가 새로운 값인 4,5,6을 할당해도 a가 참조하는 1,2,3은 영향을 받지 않는다.
두번째 예제와 세번째 예제의 차이는 두번째는 단순값이 들어간 경우라 공유된 값이 변경된 것이고,
세번째 예제는 객체가 아예 생겨서 각각 다른 값을 참조하는 레퍼런스가 되었다는 것이 내가 이해한 부분이다.
function test(a) {
a.push(4);
a; // [1,2,3,4]
a = [4,5,6];
a.push(7);
a;
}
var b = [1,2,3];
test(b);
b; // [1,2,3,4]
인자로 객체가 전달될 때도 마찬가지이다. 위의 예제와 달라보이지만 객체가 인자로 전달되어 값이 변경되었을 뿐이다.
언뜻보면 b의 답이 [4,5,6,7]일 것같지만 답은 [1,2,3,4]이다.
b의 1,2,3값이 a에게 인자로 들어가면 a와 b는 동일한 값을 가리키는 별도의 레퍼런스이다.
그래서 4,5,6으로 바꿔주어도 달라지는 것이 없다. 그렇다면 어떻게해야 값을 바꿀 수 있을까?
function test(a) {
a.push(4);
a;
a.length = 0 // 기존 배열을 비운다.
a.push(4,5,6,7);
a;
}
var b = [1,2,3];
test(b);
b;
요약
1. typeof 연산자에서 null은 null타입이 아니라 object타입을 반환한다. (버그)
2. null값을 가진 변수를 부정하면 true가 된다.
3. 자바스크립트는 타입 강제를 하지 않는다. 값에는 타입이 있으나, 변수에는 타입이 없다.요약
배열
1. 자바스크립트에서 배열은 어떤 타입의 값이라도 담을 수 있다.
2. 배열에 키/프로퍼티 문자열을 추가할수는 있으나 length가 증가하지는 않는다.
3.키로 넣은 문자열 값이 10진수 숫자로 타입이 바뀌면, 숫자를 사용한 것 같은 결과가 나온다.
문자열
1. 문자열과 문자의 배열은 다르다. 문자열은 불변값, 배열은 가변값이다.
숫자
1. void 연산자를 통해 undefinde를 얻어낼 수 있다.
2. NaN은 '숫자 아님'이 아니라 '실패한 숫자'라고 정의해야한다.
3. 값의 타입만으로 값-복사, 레퍼런스-복사 중 하나가 결정된다. 값 타입을 잘 정해야한다.
출처 : 타입과 문법, 스코프와 클로저
you don't know js
'프로그래밍 > JavaScript' 카테고리의 다른 글
자바스크립트 핵심 개념 : 호이스팅 (0) | 2020.12.16 |
---|---|
자바스크립트 핵심 개념 : 데이터 타입 기본형/참조형 (0) | 2020.12.16 |
[javascript] 네이티브 : 객체 래퍼 네이티브에 대하여 (0) | 2020.12.01 |
[javascript] 타입 : 내장 타입 7가지 / 변수에는 타입이 없다. (0) | 2020.11.30 |
Ajax data를 Controller에서 받는 두 가지 방법 : Vo / Map (1) | 2020.10.27 |