러닝 자바스크립트

리터럴과 변수 상수, 데이터 타입

숫자

문자열

Symbol

심볼은 유일한 토크을 나타내기 위해서 ES6 에서 도입한 새 데이터 타입입니다. 심볼은 항상 유일합니다. 다른 어떤 심볼과도 일치하지 않습니다. 이런 면에서 심볼은 객체와 유사합니다. 객체는 모두 유일합니다. 항상 유일하다는 점을 제외하면 시몹ㄹ은 원시 값의 특징을 모두 가지고 있으므로 확장성 있는 코드를 만들 수 있습니다.

심볼은 Symbol()생성자로 만듭니다. 원한다면 생성자에 간단한 설명을 추가할 수 있습니다. - 자바스크립트의 객체지향 프로그램에 익숙하다면 심볼을 만들때 new 키워드를 사용할 수 없으며, 대문자로 시작하는 식별자는 new 와 함께 쓴다는 불문율의 예외임을 새로 기억해야 합니다. -

const RED = Symbol('The color of a sunset');
const ORANGE = Symbol('The color of a sunset');
RED === ORANGE; // false

null 과 undefined

null 과 undefined 모두 존재하지 않는 것을 나타냅니다. 일반적인 규칙을 제시한다면, null은 프로그래머에게 허용된 데이터 타입이며 undefined 자바스크립트 자체에서 사용한다고 기억하십시오. 이 규칙이 강제는 아닙니다. 프로그래머도 언제든 undefined를 사용할 수 있지만, 꼭 필요한 때만 사용하도록 주의해야 합니다. 필자가 변수에 직접 undefined 를 할당하는 경우는, 아직 값이 주어지지 않은 변수의 동작을 고의로 흉내내야 할 때 뿐입니다. 변수의 값을 아직 모르거나 적용할 수 없는 경우에는 대부분 null이 더 나은 선택입니다. 초보 프로그래머들은 불확실할때는 null을 사용하라고 배우니까요, 변수를 선언하기만 하고 명시적으로 값을 할당하지 않으면 그 변수에는 기본적으로 undefined가 할당 됩니다.

객체

객체의 본질은 컨테이너 입니다. 컨테이너의 내용물은 시간이 지나면서 바뀔수 있지만 내용물 -프로퍼티- 이 바뀐다고 컨테이너가 바뀌는 건 아닙니다. 프로퍼티 값도 객체가 될 수 있습니다.

객체지향 프로그래밍(OOP)에 익숙하다면 자바스크립트 객체를 OOP 에 어떻게 사용하는지 궁금할 겁니다. 지금은 객체를 범용 컨테이너라고 생각하십시오. OOP 에 대해서는 9 장에서 설명합니다.

Number, String, Boolean 객체

이 장 초반에서 숫자와 문자열, 불리언에는 각각 대응하는 객체타입 Number, String, Boolean 이 있다고 언급했습니다. 이들 객체에는 두가지 목적이 있습니다. 하나는 Number.INFINITY 같은 특별한 값을 저장하는 것이고, 다른 하나는 함수 형태로 기능을 제공하는 것입니다.

CONST s = "hello";
s.toUpperCase();  // "HELLO"

위 예제의 s 는 마치 객체처럼, 즉 함수 프로퍼트를 가진 것처럼 보입니다. 하지만 우리는 s 가 분명 문자열 타입임을 알고 있습니다. 자바스크립트는 일시적인 String 객체를 만든겁니다. 이 임시 객체에 toUpperCase 함수가 들어있습니다. 자바스크립트는 함수를 호출하는 즉시 임시 객체를 파괴합니다. 객체가 임시로 만들어진다는 사실은 다음과 같이 문자열에 프로퍼티를 할당해 보면 알 수 있습니다.

const s = 'hello';
s.ration = 3; // 임시객체 생성
s.rating; // 생성되자마자 파괴되어 undefined 출력

숫자로 바꾸기

  1. Num 사용
    const numbStr = '33.3';
    const num = Number(numbStr);
    
  2. parseIntparseFloat함수를 사용
    • 장점 : 기수(10 진수, 16 진수)를 param 으로 넘길 수 있음
    • const b = parseInt("3a", 16) 16 진수 3a 를 10 진수로 바꿉니다.
  3. Date 객체를 숫자로 바꿀때는 valueOf() 메서드를 사용합니다.
    const d = new Date();
    d.valueOf();
    

문자열로 반환

Date 객체의 toString()객체는 쓸만한 결과를 반환. 객체의 toString 을 [object Object]를 반환하기 때문에 9 장에서 이 것을 수정해서 유용한 문자열 표현을 반환하게 할 수 있다.

자바스크립트의 숫자는 모두 더블형식

표현식과 연산자

비교 연산자

숫자 비교

아래 결과는 영원히 실행된다.

while (true) {
  n += 0.1;
  if (n === 0.3) break;
}

따라서 Number.EPSILON 과 관계 연산자를 사용해서 ‘느슨하게’ 비교해야 한다.

while (true) {
  n += 0.1;
  if (Math.abs(n - 0.3) < Number.EPSILON) break;
}
3 + 5 + "8" // 문자열 "88"
"3" + 5 + 8 // 문자열 "358"

거짓

자바스크립트에서 거짓 값은 다음과 같습니다.

이들 외에 모든 값은 참

참 값은 값

단축평가

const skipIt = true;
let x = 0;
const result = skipIt || x++;

위 예제의 결과는 result 는 true 이고, 단축 평가가 일어나므로 증가 연산자에 해당하는 표현식은 실행되지 않고 x 의 값은 그대로 0 이 된다. skipIt을 false 로 바꾸면 x 값은 증가한다.

const doIt = true;
let x = 0;
const result = doIt && x++;

위 AND 연산자에서는 result 의 결과는 false가 아닌 0 이다. 피연산자가 불리언이 아니라면, 결과를 겨정한 값이 반환된다. 위와 같은 특징때문에 아래와 같은 패턴이 자주 쓰인다.

const options = suppliedOptions || { name: 'default' };

typeof 연산자

typeof 연산자는 피연산자의 타입을 나타내는 문자열을 반환한다. 이 연산자는 자바스크립트의 일곱가지 데이터 타입(undefined, null, 불리언, 숫자, 문자열, 심볼, 객체)을 정확히 나타내지 못하며 끝없는 혼란을 초래했고 계속 비판을 받았습니다.

typeof 연산자는 typeof null 을 “object”라고 판단하는데, 이런 행동은 버그라고 해도 할 말이 없습니다. null 은 당연히 객체가 아니라 원시 값입니다. typeof null 이 “object”라고 판단하는데 이런 행동은 버그라고 해도 할말이 없습니다. null 은 당연히 객체가 아니라 원시 값입니다. typeof null 이 “object”를 반환한다는 사실을 이용하는 코드가 너무 많이 생겨서 이제는 돌이킬 수 없게 됐고, 명세에 수록됐으므로 바꿀수도 없습니다.

typeof 는 배열과 배열 아닌 객체도 정확히 구분하지 못합니다. 함수(객체의 특별한 타입)는 정확히 식별하지만, typeof []는 “object”를 반환합니다.

해체 할당

const obj = { b: 2, c: 3, d: 4 };

// 해체할당
const { a, b, c } = obj;
console.log(a); // undefined
console.log(b); // 2
console.log(c); // 3
console.log(d); // ReferenceError

객체 해체는 할당만으로도 이뤄질 수도 있지만 그럴려면 반드시 괄호를 써야 합니다. 괄호를 쓰지 않으면 자바스크립트는 표현식 좌변을 블록으로 해석합니다.

const obj = {b:2, c:3, d:4};
let a, b, c;

// 에러
{a, b, c} = obj;

// 동작
({a, b, c} = obj);

배열을 해체할 때는 배열 요소에 대응할 변수 이름을 마음대로 쓸 수 있으며 이들은 배열 순서대로 대응합니다.

const arr = [1, 2, 3];

//배열 해체 할당
let [x, y] = arr;
x; // 1
y; // 2
z; // ReferenceError

확산 연산자 (…)를 이용하면 남은 배열 요소를 모두 할당합니다.

const arr = [1, 2, 3, 4, 5];

let [x, y, ...rest] = arr;

x; // 1
y; // 2
rest; // [3,4,5]

객체와 배열 연산자

표현식과 흐름 제어 패턴

if…else 문의 목적이 변수의 값을 얻는 것이라면 3 항 연산자를 쓰는 편이 좋습니다.

if 문을 단축평가하는 OR 표현식으로 바꾸기. 할당이 주 목적인 if 문은 단축평가를 사용하는 OR 표현식을 써서 간결하게 줄일 수 있습니다. 3 항 연산자는 if…else 문보다 거의 항상 더 좋지만, 단축 평가는 뚜렷하게 무엇이 좋다고 말하기는 어렵습니다.

if (!options) options = {};

앞으 코드는 다음과 같이 쓸수 있습니다.

options = options || {};

6장 함수

호출과 참조

함수 식별자 뒤에 괄호를 쓰면 자바스크립트는 함수를 호출하려 합니다. 괄호를 쓰지 않으면 참조하는 것이며 실행되지 않습니다.

getGreeting(); // 호출하려 합니다.
getGreeting; // 참조하려 합니다.

함수를 호출하지 않고 다른 값과 마찬가지로 참조하기만 할 수 있다는 특징은 자바스크립트를 매우 유연한 언어로 만듭니다.


let o = {
    message : 'c';
}

function f(o){
    o.message = 'a'; // 바깥에 있는 o를  o가 서로 다른 메모리 주소를 가르킨다. 위 o와 아래 o는 주소가 다르다.
    o = { // 기존 o의 메모리 주소를 지우고 새 객체를 할당한다.
        message = 'b'
    };
    console.log(o.message);
}

console.log(o.message);  // c
f(o);                    // b 
console.log(o.message); // a <-- b가 나오지 않는다.

이 예제를 이해하는 핵심은 함수 내부의 매개변수 o와 바깥의 변수 o가 다르다는 겁니다. f를 호출하면 둘은 같은 객체를 가르키지만, f 내부에서 o에 할당한 객체는 새로운 전혀 다른 객체입니다. 함수 바깥의 o는 여전히 원래 객체를 가리키고 있습니다.

자바스크립트의 원시 값을 값 타입(value type)이라고 말합니다. 원시 값을 전달할 때 값이 복사되기 때문입니다. 객체는 참조 타입(reference type)이라 부릅니다. 객체를 전달할때 두 변수는 같은 객체를 가리키기 때문입니다.

매개변수가 함수를 결정하는가?

여러 언어에서 함수의 시그니처에는 매개변수가 포함됩니다.(오버로딩).

정해진 매개변수보다 적은 숫자를 할당하면 암시적으로 undefined가 할당 됩니다.

매개변수 해체

5장에서 해체 할당에 관해 배웠듯, 매개변수도 해체할 수 있습니다.

function getSentence({subject, verb, object}) {
    return `${subject} ${verb} ${object}`;
}

const o = {
    subject = "I",
    verb = "love",
    object : "Javascript",
}

getSentence(o); // output : "I love javascript"

배열도 해체할 수 있습니다.

function getSentence([subject, verb, object]) {
    return `${subject} ${verb} ${object}`;
}

const arr = ["I", "love", "Javascript"];

getSentence(arr); // output : "I love javascript"

ES5에서는 함수 바디 안에서만 존재하는 특별한 변수 ARGUMENTS를 사용해서 확산과 비슷한 일을 할 수 있습니다. ES6에서는 확산 매개변수를 사용해 이런 약점을 해결했으므로 arguments보다 확산 매개변수 ...words를 쓰는 것이 좋습니다.

매개변수 기본값

ES6에서는 기본값을 지정할 수 있습니다.

function(a, b = "default", c=3) {
    return `${a} - ${b} - ${c}`
}

f(); // undefined - default - 3

객체의 프로퍼티인 함수

객체의 프러퍼티인 함수를 메서드라고 불러서 일반적인 함수와 구별합니다. 함수와 메서드 사이에는 다른 차이도 있는데 그건 나중에 다시 설명합니다.

const o = {
    name : "Wallace", // 원시값 프로퍼티
    bark : function() { // 함수 프로퍼티(메서드)
        return 'woof!';
    }}

ES6에서는 간편하게 추가할 수 있습니다.

const o = {
    name : "Wallace", // 원시값 프로퍼티
    bark() { return 'WOOF!';}

this 키워드

this는 일반적으로 객체지향 프로그래밍 개념에 밀접한 연관이 있습니다.

일반적으로 this는 객체의 프로퍼티인 함수(메서드)에서 의미가 있습니다. 메서드 안에서 this는 호출한 메서드를 소유하는 객체가 됩니다.