ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 혼자 공부하는 자바스크립트 6장 - 객체
    자바스크립트/혼자 공부하는 자바스크립트 2021. 8. 1. 18:03

    객체

    이름name과 값value으로 구성된 속성property을 가진 자바스크립트의 기본 데이터 타입

    자바스크립트에서 여러 자료를 다룰 때는 객체를 사용한다. 여러 자료를 다룰 수 있는 배열 역시 객체이다. typeof []를 실행하면 object를 출력한다.

    객체는 중괄호{}로 생성하며, 키: 값의 형태의 자료를 ,로 연결해서 입력한다.

    const person = {
      name: "Bob",
      age: 32,
      handsome: true,
      interests: ['music', 'skiing'],
      bio: function() {
        alert(`${this.name} is ${this. age} years old. He likes ${this.interests[0]} and ${this.interests[1]}.`)
      },
    };

    객체의 속성에 접근하는 방법은 person["name"]처럼 배열의 인덱스에 접근하는 것과 유사하게 대괄호를 통해서도 가능하고, person.name와 같이 .을 통해서도 가능하다.

     

    속성과 메소드

    배열 내부의 값은 요소element라고 하지만, 객체 내부의 값은 속성property이라고 한다. 속성은 위의 예시에서 볼 수 있듯 문자열, 숫자, 배열, 함수 등 모든 형태의 자료형을 가질 수 있다.

    이때, 속성 중 함수 자료형인 속성을 특별히 메소드라고 부른다.

     

    메소드 내부에서 this 키워드 사용하기

    메소드 내에서 자기 자신이 가진 속성을 출력하고 싶을 때는, 자신이 가진 속성임을 분명히 표시하기 위해 this 키워드를 사용한다.

    위의 예시에서 person.bio를 참고.

     

    동적으로 객체 속성 추가/ 제거

    객체를 생성한 후에 속성을 추가/제거하는 것을 '동적으로 속성을 추가/제거한다'라고 표현한다.

    동적으로 객체 속성 추가하기

    객체.속성 = 값

    동적으로 객체 속성 제거하기

    delete 객체. 속성
    const person = {};
    
    person.name = "Bob";
    person.age = 32;
    person.handsome = true;
    
    delete person.handsome;
    
    console.log(JSON.stringify(person, null, 2));
    // {
    //        "name": "Bob",
    //        "age": 32
    // }

     

    메소드 간단 선언 구문

    위의 예시에선 메소드: function () { }의 형태로 만들었지만, 최신 버전의 자바스크립트에서는 조금 더 쉽게 선언할 수 있는 전용 구문이 있다.

    const 객체 = {메소드(매개변수) { }}

    이 방법으로 위의 예시를 수정하면 다음과 같다.

    const person = {
      name: "Bob",
      age: 32,
      handsome: true,
      interests: ['music', 'skiing'],
      bio() {
        alert(`${this.name} is ${this. age} years old. He likes ${this.interests[0]} and ${this.interests[1]}.`)
      },
    };
    
    person.bio();        // Bob is 32 years old. He likes music and skiing.

     

    화살표 함수를 사용한 메소드

    기본적으로 화살표 함수는 메소드로 사용하지 않는다. 이는 익명 함수와 화살표 함수가 this 키워드를 다루는 방식이 다르기 때문이다.

    const person = {
      name: "Bob",
      sayHi() {
        console.log(`Hi ${this.name}`);
      },
      sayHello: () => {
        console.log(`Hello ${this.name}`);
      },
    };
    
    person.sayHi();        // Hi Bob
    person.sayHello();        // Hello 
    • 여러 문서에서 반복적으로 찾을 수 있는 표현은, 화살표 함수에는 고유한 this가 없다는 것이다.
    • 화살표 함수에는 고유한 this가 없기 때문에, 화살표 함수 외부에서 this를 가져온다. 즉, 위의 화살표 함수에선 person 객체 외부에서 this를 가져오기 때문에, window 객체에서 this를 가져온다.
    • 모던 자바스크립트 튜토리얼: 메서드와 this, 화살표 함수 다시 살펴보기

     

    객체의 속성과 메소드 사용하기

    자바스크립트에서 사용하는 자료는 크게 기본 자료형primitives과 객체 자료형object으로 구분할 수 있다.

    • 기본 자료형
      • 숫자
      • 문자열
    • 객체 자료형
      • 함수
      • 배열
      • 이외 전부

    객체 자료형

    속성과 메소드를 가질 수 있는 모든 것은 객체다. 그러므로 속성을 지정할 수 있는 배열 역시 객체이다.

    const a = [];
    a.sample = 10;
    a.sample;        // 10
    
    typeof a;        // "object"
    Array.isArray(a)        // true

    함수에도 속성을 지정할 수 있다. 단 typeof 함수로 자료형을 확인하면 "object"가 아니라 "function"으로 나오는데, 이는 실행이 가능한 객체이기 때문이다. 함수는 객체의 특성을 완벽하게 가지고 있으므로, 자바스크립트에선 함수를 일급 객체에 속한다고 표현하기도 한다.

     

    기본 자료형

    실체가 있는 것(즉, undefinednull 등이 아닌 것) 중에 객체가 아닌 것을 기본 자료형이라고 하며, 숫자, 문자열, 불이 해당한다. 기본 자료형은 객체가 아니므로 속성을 가질 수 없다. 억지로 추가해 출력해도 undefined가 출력되며 추가되지 않는다.

     

    기본 자료형을 객체로 선언하기

    자바스크립트는 기본 자료형을 객체로 선언하는 방법을 제공한다.

    const 객체 = new 객체 자료형 이름();
    new Number(10);
    new String("문자열");
    new Bollean(true);

    이렇게 사용하면 숫자 객체, 문자열 객체, 불 객체를 생성한 것이다. 이렇게 생성된 객체는 기존 연산자를 모두 사용함과 더불어 속성과 메소드 역시 활용할 수 있다.

    const f = new Number(273);
    f.sample = 10;
    f.sample;        // 10
    f.valueOf()        // 273
    
    f;        // Number { 273, smaple: 10 }
    f + 1;        // 274

     

    기본 자료형의 일시적 승급

    문자열.length, 문자열.bold()와 같이, 기본 자료형 뒤에 .속성이나 .메소드()를 호출하려 하면 자바스크립트는 일시적으로 기본 자료형을 객체로 승급시킨다. 이러한 승급은 일시적이다. 즉, 기본 자료형은 속성과 메소드를 사용할 수는 있지만, 속성과 메소드를 추가로 가질 수는 없다.

    const b = "String";        // undefined
    b.sample = 10;        // 10        일시적 승급
    b.sample        // undefined        객체 승급이 일시적이어서 sample 속성이 사라졌다.

     

    프로토타입으로 메소드 추가하기

    prototype 객체에 속성과 메소드를 추가하면 모든 객체(와 기본 자료형)에서 해당 속성과 메소드를 사용할 수 있다.

    객체 자료형 이름.prototype.메소드 이름 = function () {
    
    }
    Number.prototype.sample = 10;        // 10
    const i = 273;        // undefined
    i.sample        // 10

    위의 예시에서, Number.prototype에 속성을 추가하는 것은 숫자 객체 전체에 속성을 추가하는 것이고, 이는 객체 자료형이 아닌 기본 자료형 숫자에서도 속성을 사용할 수 있음을 뜻한다.

    모든 숫자 자료형(이거나 다른 기본 자료형)이 어떤 속성을 공유할 필요는 없기 때문에, 일반적으로 프로토타입에 속성을 추가하지 않는다. 하지만 프로토타입에 메소드를 추가하면 다양하게 활용할 수 있다.

    • MDN: Object prototypes 에선 "일반적인 방식으로는 속성은 생성자에서, 메소드는 프로토타입에서 정의합니다. "라고 설명한다.
    • 모던 자바스크립트 튜토리얼 에선 "모던 프로그래밍에서 네이티브 프로토타입 변경을 허용하는 경우는 딱 하나뿐입니다. 바로 폴리필을 만들 때입니다."라고 설명한다. 폴리필은 자바스크립트 명세서에 적혀있는 메소드와 동일한 기능을 하는 것을 말한다. 즉, 자바스크립트 명세서에는 적혀있는데, 특정한 상황에서 해당 기능이 구현되어 있지 않을 때에만 프로토타입을 추가(변경)하라는 것이다.
      • 프로토타입은 전역으로 영향을 미치기 때문에 여러군데에서 조작할 경우 충돌이 날 가능성이 높기 때문이다.

     

    Number.prototype.power = function (n = 2) {
      return this.valueOf() ** n
    }
    
    const a = 2;
    
    a.power();        // 4
    a.power(3);        // 8
    a.power(4);        // 16

    ** 는 제곱 연산자로, 숫자 ** n과 같은 형태로 쓰였을 때 숫자를 n제곱한다.

    숫자 객체에서 꺼냈음을 명확하게 하기 위해 valueOf() 메소드를 사용했고, 기본값이 2인 기본 매개변수 n을 사용하였다.

    문자열의 indexOf() 메소드는 찾고자 하는 문자열의 존재 여부를 파악할 수 있는 메소드로, 있다면 해당 문자열의 시작하는 인덱스를 출력하고, 없으면 -1을 출력한다. 즉, 문자열.indexOf() >= 0 등의 코드를 사용했을 때, 결과가 true라면 어떤 문자열에 찾고자 하는 문자열이 있는 것이고, false라면 없는 것이다.

    이를 활용해, String.prototype.contain = function (data) { return this.indexOf(data) >= 0 }, Array.prototype.contain = function (data) { return this.indexOf(data) >= 0 } 의 코드로 contain() 메소드를 프로토타입에 추가하면, "안녕".contain("안녕") 식으로 단순히 truefalse 값을 리턴 받을 수 있다.

     

    Number 객체

    Number 객체에서 자주 사용하는 기본 메소드들은 다음과 같다:

    toFixed(n)

    소수점 이하 n자리까지 출력하고 싶을 때 사용한다.

    isNaN(), isFinite()

    NaN 자료형은 Number.isNaN(x)을 통해서만 확인할 수 있다. NaN === NaN 역시 false를 반환한다.

    const m = Number("String");        // undefined
    m;        // NaN
    m === NaN;        // false
    Number.isNaN(m)        // true

    Number.isFinite(x) 는 무한대를 확인할 수 있는 메소드이다. 무한대에는 양의 무한대 숫자와 음의 무한대 숫자 두가지가 있는데, 이 두가지 경우에는 false를 반환하고, 그 외의 유한한 숫자에는 true를 반환한다.

     

    String 객체

    x.trim()

    문자열 양쪽 끝의 공백(띄어쓰기, 줄바꿈 등)을 제거하는 메소드이다.

    split(매개변수)

    문자열을 매개변수로 구분해 배열로 리턴하는 메소드이다.

    const genres = "Horror,Romance,Action"
    const splitedGenres = genres.split(,);
    splitedGenres;        // (3) ["Horror", "Romance", "Action"]

    이 외에도 length 속성, indexOf() 메소드 등이 있다.

     

    JSON 객체

    JSON은 JavaScript Object Notation의 약자로, 인터넷에서 문자열로 데이터를 주고받는 다양한 자료 표현 방식 중 현재 가장 많이 사용되고 있는 방식이다.

    이름에서 알 수 있듯, JSON은 자바스크립트의 배열과 객체를 활용해 어떤 자료를 표현하는 형식이다. 단, 추가 규칙이 있다.

    • 값을 표현할 때 문자열, 숫자, 불 자료형만 사용할 수 있다.
    • 문자열은 반드시 큰따옴표""로 만들어야 한다.
    • 키에도 반드시 따옴표를 붙여야 한다.

    자바스크립트 객체를 JSON 문자열로 변환할 때는 JSON.stringify() 메소드를 사용한다.

    JSON.stringify(value[, replacer[, space]])

    일반적으로 매개변수를 하나만 사용해서 활용한다. replacer는 객체의 특정한 속성만 추출하고 싶을 때 사용하며, null을 입력하면 모든 속성을 추출한다. space는 들여쓰기 칸을 설정한다.

    console.log(JSON.stringify({ x: 5, y: 6 }, null, 2));
    // {
    //    "x": 5,
    //    "y": 6
    // }

    반대로, JSON 문자열을 자바스크립트 객체로 전개할 때는 JSON.parse() 메소드를 사용한다.

    const json = JSON.stringify({ x: 5, y: 6 }, null, 2);
    
    console.log(JSON.Parse(json));
    // {x: 5, y: 6}
    //         x: 5
    //        y: 6
    //        __proto__: Object

     

    Math 객체

    수학과 관련된 기본적인 연산을 할 땐 Math 객체를 이용한다. 속성으로는 Math.PI, Math.e와 같은 수학 상수가 있으며, 메소드로는 Math.sin(), Math.cos(), Math.tan() 같은 삼각함수도 있다. 랜덤한 숫자를 생성할 때 Math.random() 메소드를 사용하는데, 이때 0 이상 1 미만의 랜덤한 값이 나오므로 그 이상의 범위에서 활용하려면 여러 처리를 해야 한다.

    Math.ceil(Math.random()*10)        // 0에서 10 이하의 랜덤 정수가 나온다.

     

    외부 script 파일 읽어들이기

    HTML

    <script src="./test.js"></script>

     

    Lodash 라이브러리

    다른 사람들이 만든 다양한 함수와 클래스를 묶어서 제공해주는 것을 외부 라이브러리라고 부른다.

    유틸리티 라이브러리는 개발할 때 보조적으로 사용하는 함수들을 제공해주는 라이브러리이다. underscroe, Lodash 등 다양한 라이브러리가 있다.

    CDN 링크 페이지에 가서 lodash.min.js의 CDN 링크를 복사해 <script src="CDN 링크"로 입력하면 Lodash 라이브러리를 사용할 수 있다.

    <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
    • CDN은 Contents Delivery Network의 약자이다. 전 세계 여러 지역에 전송할 데이터를 준비해두고, 사용자가 데이터를 요청했을 대 가장 가까운 지역에서 데이터를 전송하는 방식이다.
    • CDN으로 전송할 때 데이터의 용량을 줄이고자 라이브러리 소개 등을 줄이고 코드를 집핑(zipping, 응축)한다. 이렇게 집핑한 버전이 min 버전이다.

    Lodash 라이브러리는 _ 식별자에 sortBy() 등 여러 메소드를 담아 놨다.

    Lodash 라이브러리 외에도 Luxon, date-fns, Handsontable, D3.js, ChartJS, Three.js 등 여러 라이브러리가 있다. jQuery, React.js 도 모두 라이브러리다.

     

    객체와 배열 고급

    속성 존재 여부 확인

    객체에 없는 속성에 접근하면 undefined 자료형이 나오게 되므로, 조건문으로 확인하면 속성 존재 여부를 확인할 수 있다.

    if (object.property) {
      console.log(`property 속성이 있습니다.`)
    } else {
      console.log(`property 속성이 없습니다.`)
    }

    단 이 방법은 속성이 0, false 등이 아닐 때만 사용가능하다. 이와 같은 전제라면 다음 조건문을 사용할 수 있다.

    object.property || console.log(`property 속성이 없습니다.`)
    • OR 연산자||를 여러 개 체이닝(chaining) 하면 첫 번째 truthy를 반환하는 것을 이용한 문장이다.
    • 만일 object.property가 존재하지 않으면 falsy한 값인 undefined이므로, console.log()가 실행된다.

    이를 응용하면 기본 속성을 지정할 수 있다.

    object.property = object.property || "기본 속성"

     

    배열 기반의 다중 할당

    최신 자바스크립트부터 배열과 비슷한 작성 방법으로 한 번에 여러 개의 변수에 값을 할당하는 다중 할당 기능이 추가되었다.

    [식별자, 식별자, 식별자, ...] = 배열
    let [a, b] = [1, 2];
    console.log(a, b);        // 1, 2
    
    [a, b] = [b, a];
    console.log(a, b);        // 2, 1
    
    let arrayA = [1, 2, 3, 4, 5];
    const [a, b, c] = arrayA;
    console.log(a, b, c);        // 1, 2, 3

    배열의 크기가 달라도 요소에 값을 할당할 수 있으며, 앞에서부터 순서대로 할당된다.

     

    객체 기반의 다중 할당

    객체 내부에 있는 속성을 꺼내서 변수로 할당할 때 사용할 수 있는 코드이다.

    { 속성, 속성 } = 객체;
    { 식별자 = 속성, 식별자 = 속성 } = 객체;
    const person =  {
      name: "Kim",
      age: 32,
      handsome: true,
    };
    
    const { name, age } = person;
    console.log(name, age);        // Kim 32
    
    const { a = name, b = age } = person;
    console.log(a, b);        // Kim 32

     

    배열 전개 연산자

    기본 자료형과는 달리, 배열을 포함한 객체에 자료를 할당, 저장, 복사 등을 하면 저장되어있는 '메모리 주소’인 객체에 대한 '참조 값’이 저장된다.

    const 물건_200301 = ["우유", "식빵"];
    const 물건_200302 = 물건_200301;
    
    물건_200302.push("고구마");
    물건_200302.push("토마토");
    
    console.log(물건_200301);        // (4) ["우유", "식빵", "고구마", "토마토"]
    console.log(물건_200302);        // (4) ["우유", "식빵", "고구마", "토마토"]

    물건_200302물건_200301의 배열을 복사하고 200302push()메소드로 자료를 추가했다. 하지만 console.log 했을 때 두 배열의 값은 동일하게 출력된다. 값만 복사된 독립적 객체가 아니라, 동일한 참조값을 가진 객체이기 때문이다.

    독립적으로 작동한 두 배열을 만드려면 깊은 복사, 즉 클론을 만들어야 한다. 최신 자바스크립트에선 전개 연산자를 사용해 입력하면 깊은 복사를 할 수 있다.

    [...배열]
    const 물건_200301 = ["우유", "식빵"];
    const 물건_200302 = [...물건_200301];
    
    물건_200302.push("고구마");
    물건_200302.push("토마토");
    
    console.log(물건_200301);        // (2) ["우유", "식빵"]
    console.log(물건_200302);        // (4) ["우유", "식빵", "고구마", "토마토"]

     

    객체 전개 연산자

    객체도 깊은 복사를 할 때 전개 연산자를 사용할 수 있다.

    {...객체}
    const personKim = {
      name: "Kim",
      age: 32,
      handsome: true,
    };
    
    const personPark = {...personKim};
    personPark.name = "Park";
    personPark.age = 26;
    
    console.log(JSON.stringify(personKim));        // {"name":"Kim","age":32,"handsome":true}
    console.log(JSON.stringify(personPark));        // {"name":"Park","age":26,"handsome":true}

     

    깊은 복사를 하면서 자료를 수정, 추가 할 수 있다.

    {...객체, 자료, 자료, 자료}
    const personKim = {
      name: "Kim",
      age: 32,
      handsome: true,
    };
    
    const personPark = {
      ...personKim,
      name: "Park",
      age: 26,
      nationality: "ROK"
    };
    
    console.log(JSON.stringify(personKim));        // {"name":"Kim","age":32,"handsome":true}
    console.log(JSON.stringify(personPark));
            // {"name":"Park","age":26,"handsome":true,"nationality":"ROK"}

     

    이때 전개 순서가 중요한데, 자료 수정 및 추가를 한 뒤 전개를 해버리면 전개된 객체의 속성이 새로 작성한 속성을 덮어 쓸 수도 있으니 주의한다.

    const personKim = {
      name: "Kim",
      age: 32,
      handsome: true,
    };
    
    const personPark = {
      name: "Park",
      age: 26,
      nationality: "ROK",
      ...personKim,
    };
    
    console.log(JSON.stringify(personKim));        // {"name":"Kim","age":32,"handsome":true}
    console.log(JSON.stringify(personPark));
            // {"name":"Kim","age":32,"nationality":"ROK","handsome":true}

    전개를 뒤에서 해서 personKim의 속성이 앞서 작성한 name, age 속성을 덮어써버렸다.

    댓글

Designed by Tistory.