러닝 자바스크립트 3장에 해당되는 부분이며, 읽으면서 자바스크립트에 대해 새롭게 알게된 것과 기록하고 싶은 부분을 정리한 내용입니다.
null
과 undefined
는 자바스크립트의 특별한 타입으로 모두 존재하지 않는 것을 나타낸다. null
이 가질 수 있는 값은 null
하나이며, undefined
가 가질 수 있는 값도 undefined
하나뿐이지만 둘은 서로 다른 데이터 타입으로 분리된다.
null
은 원시값으로 값이 비어있음을 의도적으로 표현하는 것이다. undefined
는 값이 지정되지 않은 경우를 의미하지만, null
은 해당 변수가 어떤 객체도 가리키고 있지 않다는 것을 의미한다.
undefined는 원시값으로 선언한 후에 값을 할당하지 않은 변수나 값이 주어지지 않은 인수에 자동으로 할당된다. 이 값은 전역 객체의 속성 중 하나로, 전역 스코프에서의 변수이기도 하다.
let currentTemp; //undefined
typeof undefined //'undefined'
typeof null //'object'
저자는 변수에 직접 undefined를 할당하는 경우는 값이 주어지지 않은 변수의 동작을 고의로 흉내 내야 할 때이며, 이외에는 대부분 null을 할당하는 것이 더 나은 선택이라고 권장한다.
원시 타입과 다르게, 객체
는 여러 가지 값이나 복잡한 값을 나타낼 수 있으며, 변할 수도 있다. 객체
에는 {와 }를 사용하는 리터럴 문법이 있으며 안의 내용이 바뀌어도 여전히 같은 객체이다.
객체
의 콘텐츠는 프로퍼티 또는 멤버라고 불린다. 프로퍼티는 키와 값으로 구성되고, 프로퍼티의 이름은 문자열 혹은 심볼이어야 하며, 값은 어느 타입이든 상관이 없고 객체여도 상관 없다.
프로퍼티의 값에 접근을 할 때는 두 가지 방법이 있는데, 프로퍼티의 이름이 유효한 식별자일 경우(식별자 규칙을 지킨) . 또는 [ ]로 접근이 가능하고 프로퍼티의 이름이 유효하지 않은 식별자일 경우 [ ]로 접근이 가능하다.
const obj = {};
obj.color = "yellow";
obj["not an identifier"] = 3;
obj["not an identifier"] //3
obj.color //"yellow"
obj["color"] //"yellow"
delete obj.color; //프로퍼티 제거
자바스크립트에는 원시 타입인 숫자와 문자열, 불리언에는 각각 대응하는 객체 타입 Number, String, Boolean이 있다. 이들 객체에는 두 가지 목적이 있는데 하나는 Number.INFINITY 같은 특별한 값을 저장하는 것이고, 다른 하나는 함수 형태로 기능을 제공하는 것이다.
const s = "hello";
s.toUpperCase(); //"HELLO"
이는 마치 객체 프로퍼티의 값을 접근할 때 처럼 보이지만, 자바스크립트는 일시적인 String 객체를 만들고 이 임시 객체에 toUpperCase 함수를 넣는 과정이다. 자바스크립트는 함수를 호출하는 즉시 임시 객체를 파괴한다.
const s = "hello";
s.rating = 3; //일시적인 String 객체를 만들고 프로퍼티를 할당
s.rating; //자바스크립트는 임시 객체를 즉시 파괴하기 때문에 undefined
const numStr = "33.3";
const num = Number(numStr);
이 예제는 숫자 값을 만들 뿐, Number 객체의 인스턴스를 만드는 것이 아니다.
Number()
는 숫자를 다루고 표현할 때 사용하는 원시 래퍼 객체인 Number
가 가지고 있는 함수이다. 따라서 Number()
는 객체를 리턴하는 것이 아니라 Number를 리턴하며, new Number()
가 객체로 인스턴스를 생성하여 반환하는 것이다.
const x = Number("01");
typeof x; //'number'
const x = new Number("01");
typeof x; //'object'
Number("1") === new Number("1") //false
내장 함수인 parseInt()
와 parseFloat()
는 Number()
와 비슷하게 동작하지만, 기수를 넘겨 변환할 문자열이 몇 진수 표현인지 지정이 가능하다. 기본값은 10진수이며 숫자로 판단할 수 있는 부분까지만 변환하고, 그 뒤의 문자열은 무시된다.
const a = parseInt("16 volts",10); //16
const b = parseInt("3a",16); //58
const c = parseFloat("15.5 khp"); //15.5
원시 값
은 불변이고, 원시 값
을 복사 혹은 전달할 때는 값 자체를 복사/전달한다. 즉, 원본의 값이 바뀌더라도 사본의 값이 따라서 바뀌지 않는다.
let a = 1; //원본
let b = a; //사본
a = 2; //원본 값 변경
console.log(b); //1
a === 2 //true
값 자체를 전달하기 때문에 함수 안에서 변수의 값이 바뀌어도 함수 외부에서는 바뀌지 않은 상태로 남는다.
function change(a) {
a = 5;
}
a = 3;
change(a);
console.log(a); //3
하지만 객체
는 가변이고, 객체
를 복사 혹은 전달할 때는 객체가 아니라 그 객체를 가리키고 있다는 것(참조)를 복사/전달한다. 즉, 원본이 바뀌면 사본도 따라서 바뀐다.
let o = {a: 1}; //원본
let p = o; //사본
o.a = 2
o === p; //true
console.log(p) //{a: 2}
하지만 객체가 가리키는 것이 바뀌게 되면
let o = {a: 1}; //원본
let p = o; //사본
p === o; //true
o = {a: 2};
p === o; //false
console.log(p) //{a: 1}
4번째 줄에서 o에게 다른 것을 가리키라고 명령했기 때문에 p는 여전히 a:1를 가리키고 있다. 변수와 객체는 결코 일치하지 않는다.
객체는 참조를 전달하기 때문에 함수 안에서 객체를 변경하면 함수 외부에서도 변경된다.
function change_o(o) {
o.a = 999;
}
let o = {a: 1};
change_o(o);
console.log(o); //{a: 999}