본문 바로가기

Study/JavaScript

Object

Before Start

데이터 타입은 primitive type과 non-primitive(object) type 두 가지로 나눌 수 있다. 이 두가지 타입의 데이터는 변수에 할당된 뒤, 메모리에 저장되는 방식에 차이가 있다. primitive type을 먼저 살펴보자.

 

let myAge = 23;

 

우리가 위와 같은 코드를 작성하면, myAge는 어떤 메모리 셀 하나의 주소를 가리키고 그 메모리 셀은 23이라는 숫자를 저장한다. 이 때 메모리 셀의 크기는 1byte 라는 것을 알아두자. (1byte=8bit로 8개의 비트 정보를 저장할 수 있다. 즉 0 또는 1의 정보를 가지고 있는 bit 8개를 하나의 셀에 저장할 수 있다.)

 

const apple = {
  color: 'red', 
  price: '$1', 
  display() { // this is a method of apple
    console.log('🍎');
  }
}

 

object는 어떨까? object는 "관련있는 state와 action을 함께 묶어 둔 복합적인 데이터"를 말한다. 사과라는 객체를 만들어서 사과의 색깔, 가격, 전시 행위 등을 한 데 묶어 저장할 수 있다. 이런 복합적인 데이터는 1byte짜리 메모리 셀에 저장할 수 없기 때문에 primitive type과 다른 방식으로 메모리에 저장된다.

 

객체 데이터를 apple이라는 변수에 할당하면, apple은 어떤 메모리 셀 하나의 주소를 가리킨다. 이 과정 까지는 primitive type의 데이터와 동일하다. 다만 가리키는 주소에는 apple의 데이터가 저장되어 있지 않다. apple은 저 멀리, 메모리 중에서도 'heap'이라는 공간에 따로 저장 된다. 물론 하나의 셀이 아니라 여러 개의 셀에 거쳐 저장되어 있다. apple이 가리키는 메모리 셀에는 바로 apple의 첫번째 데이터가 저장된 heap 어딘가의 주소(reference)가 저장된다. 

 

  • 객체를 저장하는 변수(apple) => apple의 첫번째 데이터가 저장되어있는 메모리 셀의 주소, 즉 'heap' 이라는 메모리 공간의 주소가 저장되어 있음

property에 접근하는 방법 | Dot vs. [Bracket] Notation

객체에는 여러 개의 state와 action이 저장되어 있다. 여기에서 state는 property를 말하고, action은 method(함수)를 말한다. property는 key와 value로 이루어져 있는데 apple 객체를 예로 들자면, color: 'red'에서 color는 key, 'red'는 value가 된다. 이 property에 접근하는 방법은 두가지가 있다.

 

apple.price; // '$1'
apple['price']; // '$1'

 

첫번째 코드에 작성한 것을 점 표기법, 두번째 코드에 작성한 것을 괄호 표기법이라고 한다. 똑같이 apple 객체의 price라는 키에 접근해서 값을 반환하고 있다. 따라서 더 간단해 보이는 점 표기법을 사용하고 싶다는생각이 드는데, 두 표기법의 차이는 뭘까? 

 

dot notation을 이용한 접근은 접근하고자 하는 property가 존재하는 상태에서 가능하다. bracket notation을 이용하면 접근하고자 하는 property가 존재하지 않는 상태에서도 접근이 가능하다. 아래 예제 코드를 통해 이 설명에 대해 이해해 보자. 

 

function calculator(a, b, action) {
  return action(a, b)
}

 

우리는 a와 b가 무엇인지 정의하지 않았던 것처럼, action이라는 함수를 정의하지 않고 action을 실행할 수 있는 함수를 만들었다. 

 

function addValue(obj, key, value) {
  obj[key] = value; 
  return obj ;
}

 

객체에 key와 value를 추가하는 위의 함수가 정의되는 시점에서는 어떤  obj를 인자로 받고, 어떤 key와 value를 추가 할지 알 수 없다. 존재하지 않는 property에 접근한다는 것은 이런 상황을 말하는 것이다. 이 때에는 dot notation이 아니라 bracket notation을 이용해야 한다. 만약 obj.key라고 코드를 작성하게 되면, 'key'라는 이름을 가진 key가 만들어진다. 참고로 addValue 함수를 실행할 때 입력할 obj 인자는 존재하는 상태여야 한다. 사과라는 객체가 존재하는 상태에서 무게 같은 property를 추가할 수 있다는 뜻이다. 

 

addValue(apple, 'weigh', '300g');

How to create Object? | Function chapter와 함께✍

지금까지 너무 아무렇지 않게 object 데이터를 변수에 할당했기 때문에, 객체를 생성하는 방법에 대해 이야기하는 것이 이상하게 느껴질 수도 있다.

Objcet Literal

먼저 가장 흔하게 사용되는 방법은 객체 표기법(object literal)으로, 지금까지 이용한 방법이다.

 

const person = {
  name: 'hyeonJu',
  age: 23,
};

 

객체 리터럴을 이용하지 않고 객체를 생성할 수 있는 방법이 있는데, 생성자 함수(constructor function)를 이용하는 것이다. 생성자 함수가 반환하는 것은 객체 데이터이기 때문이다.  

 

function Fruit(name, emoji) {
  this.name = name;
  this.emoji = emoji;
  this.display = () => {
    console.log(`${this.emoji}`);
  };

  return this; // skipping is possible
}

const apple = new Fruit('apple', '🍏');
apple;

/*
{
  name: apple,
  emoji: '🍏',
  display, 
}
*/

 

생성자 함수의 이름(Fruit)은 대문자로 시작하도록 한다. Fruit 함수의 { 코드 블럭 } 안에는 객체에 집어 넣을 데이터의 틀을 만든다. 위의 예제 코드에서는 Fruit안에 과일의 이름과 이모지, 과일을 전시(display)하는 함수 데이터를 집어 넣는 틀을 만들었다. 

this

this라는 것은 Fruit 함수를 실행했을 때 만들어질 object를 가리킨다.

예를 들어, this.name = name; 이라고 작성한 코드에서는 Fruit 함수의 첫번째 매개변수인 name에 전달되는 값을 앞으로 만들어질 객체(this)의 name이라는 key의 value로 할당하는 일을 한다. 

new

생성자 함수를 통해 객체를 만드는 방법은 다음과 같다.

 

const cherry = new Fruit('cherry', '🍒');

Short Literal

객체의 축약 표기법을 말한다. 아무때나 사용하는 것은 아니고, 객체의 value에 전달될 변수의 이름과 key의 값이 동일할 때 사용할 수 있다.

예를 들어,

  • const x = 0;
  • const y = 0; 일 때
  • const coordinate = {x, y}; 라고 하면,
  • coordinate은 {x:0, y:0}이 된다.

Global Object

User-defined Object vs. Global Object vs. Host Object

object를 세 가지로 구분지어 보면, 사용자가 코드 내부에서 정의한 User-Defined Object, Global Object, Host Object가 된다.   

 

Global Object란 프로그래밍 언어 자체에 내장되어있는 object를 말하며, Built-in Object와 동일한 뜻으로 사용된다. 이때 global object란 global scope에 존재하는 object를 말하는데, 코드 안의 어떤 scope(코드 블럭)에서도 접근이 가능한 object라는 의미를 갖는다.

그러나 프로그래밍 언어 자체에서 제공하는 객체(APIs) 만으로 어플리케이션을 만들기에는 한계가 있기 때문에 언어의 실행환경에서도 object를 제공한다. 이를 Host Object라고 한다. JS의 경우 실행환경은 browser와 node이고 각각 web APIs와 node APIs를 제공한다. 

자주 사용하는 Global Object | MDN Global Object Reference 

Wrapper object

primitive type의 데이터는 데이터 값 하나를 갖는다. 예를 들어 const text = '안녕하세요'; 라고 했다면 text는 하나의 string data를 가리키고 있는 것이다. 우리는 때때로 이 문자열의 길이나, 2번째 글자는 무엇인지 등이 궁금해 진다. 이 때 text.length;text.charAt(1); 를 이용할 수 있다.

 

const text = '안녕하세요'; 

text.length; // 5
text.charAt(1); // 녕

 

이 코드를 잘 살펴보면, primitive data인 text에 dot notation을 이용하여 state(length)와 method(charAt)에 접근했고, 이를 실행시킨 것을 알 수 있다. 즉, primitive data를 마치 object data처럼 이용하고 있다는 것이다. 어떻게 이것이 가능한 걸까?

 

바로 wrapper 객체 덕분이다. 위처럼 primitive data에 dot notation을 이용해 어떤 프로퍼티나 메소드에 접근하는 순간, 자바스크립트는 primitive data를 객체로 변환한다. 이렇게 변환된 객체를 wrapper object라고 한다. 평소에는 primitive data로 저장되어 있다가, 필요할 때 primitive를 object로 변환하고, 다시 data 자체를 이용할 때에는 primitive type으로 돌아오기 때문에 메모리를 절약할 수 있다. primitive data를 만들 때 new 키워드를 이용하여 new String, new Number, new Boolean을 사용하면 처음부터 wrapper 객체가 변수에 할당된다. 다만 메모리의 절약 차원에서 좋은 방법은 아니기 때문에 잘 사용하지 않는다. 

 

Global Values & Functions 

본격적으로 전역(global)에서 사용되는 object에 대해 알아보기 전에, 전역에서 사용되는 값과 함수에 대해 알아보자. 

 

  • Value
    • globalThis, this
      • JS의 실행환경에서 사용하는 global object를 나타낸다.
      • browser에서는 두 값 모두 Window를 나타낸다. node의 경우는 두 값이 조금 다르지만, 일반적으로 globalThis를 이용하며 이는 node의 global object를 나타낸다. 
    • Infinity, NaN, undefined
  • Function 
    • eval('some code...') | 문자열 형식으로 전달받는 자바스크립트 코드를 평가(evaluate)하고, 그 결과를 반환한다.
    • isFinite(number) | 인자로 받은 숫자가 유한한지 아닌지 평가하고 boolean을 반환한다.
    • parse
      • parseFloat('float number') | 소수를 quote로 감싼 string을 인자로 받아 소수(number)로 변환한다.
      • parseInt('any number') | 숫자를 quote로 감싼 string을 인자로 받아 정수로 변환한다.
    • encode
      • URL: URI(어떤 Resouce를 나타내는 고유한 Identifier)의 하위개념으로, 웹 사이트의 주소를 나타내는 고유한 값이다. ASCII 문자로만 구성되어야 하기 때문에, 한글이나 특수문자가 포함되어 있는 주소의 경우, escape 처리가 필요하다. 
      • encodeURI('한글이나 특수문자가 포함된 주소')
      • decodeURI('encoded URI')
      • encodeURIComponent('부분적인 주소(예를들어 http가 포함되어 있지 않은 주소)')

 

Global Object

  1. Boolean
    • valueOf() | new 키워드를 이용해 생성한 Boolean 객체 인스턴스의 원시 값을 반환한다.  
      • falsy: 0, -0, null, NaN, undefined, ''
      • truthy: 12, 'any', {}, [] 
  2. Number
    • Static Properties
      • Number.EPSILON | 프로그램에서 숫자를 이용한 연산을 처리할 때 십진수로 입력한 숫자들은 이진수로 변환되어 계산이 되고, 다시 우리에게 십진수로 보여진다. 이진수로 변환되어 계산할 때에는 오차가 발생하는 경우가 있다(십진수 계산에서도 발생한다. 10/3 은 3.33333...의 경우처럼). 이 미묘한 오차를 나타내는 값이 바로 EPSILON이다. 
      • Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER... 
    • Static Methods
      • Number.isNaN(number), Number.isFinite(number), Number.isInteger(number)... 
    • Instance Methods
      • num.toExponential() | 지수 표기법으로 숫자를 나타낸다 
      • 숫자를 문자열로 변환한다
        • num.toString() | 문자열로 변환한다
        • num.toFixed() | 반올림 한 뒤 문자열로 변환한다
      • num.toLocaleString('ko-KR') | 특정 나라에서 사용되는 문자열로 변환한다
      • 숫자를 반올림 한다
        • num.toPrecision(자릿수) | 원하는 자릿수까지 유효하도록 반올림한다
      • 항상 소수점 이하 n번째 자리까지만 나타낸다.
  3. Math
    • Static Properties
      • Math.E | 자연로그 e의 밑
      • Math.PI | 원주율
    • Static Methods
      • Math.abs(num) | 절대값
      • 올림과 버림
        • 올림은 인자보다 큰 가장 가까운 정수를 ,버림은 인자보다 작은 가장 가까운 정수를 반환한다.
        • Math.ceil(num) | 올림
        • Math.floor(num) | 버림 
      • Math.round(num) | 반올림 
      • Math.trunc(num) | 소수점 자르기 
      • 최댓값과 최솟값
        • Math.max(num1, num2, num3...) | 최댓값  
        • Math.min(num1, num2, num3...) | 최솟값
      • Math.pow(num1, num2), num1 ** num2 | Power(거듭제곱)
      • Math.sqrt(num) | Square Root(제곱근) 
      • Math.random() | Random Number(난수) 
        • 0과 1사이의 숫자 중에 하나의 random number를 추출한다.  
  4. String
    • Instance Properties
      • text.length | 문자열의 길이
    • Instance Methods
      • text.charAt(index) | 해당하는 index(0~)에 위치하는 문자 반환 
      •  해당하는 문자의 index반환
        • text.indexOf('글자') | 해당하는 문자의 index반환, 만약 해당하는 글자가 없으면 -1을 반환
        • text.lastIndexOf('글자') | 해당하는 문자의 index를 문자열의 끝에서 부터 찾아 반환 
      • text.includes('글자') | 문자열이 해당하는 문자를 포함하고 있는지를 boolean으로 반환
      • 문자열이 해당하는 문자로 시작하는지/끝나는지를 boolean으로 반환
        • text.startsWith('글자') | 시작하는지를 반환  
        • text.endsWith('글자') | 끝나는지를 반환 
      • text.toUpperCase('문자열') | 문자열을 대문자로 반환 
      • 문자열 자르기
        • text.substring(start, end)
        • text.slice(start, end)
        • start와 end index를 지정한 뒤, 해당하는 문자열을 반환(end index는 포함X)
        • substring과 slice의 차이점
      • text.trim() | 문자열 앞뒤의 공백을 지운 뒤 문자열 반환 
      • text.split('구분자'); | 구분자를 이용해 문자열을 나누고, 각 문자열을 요소로 갖는 배열을 반환
  5. Date
    • Constructor
      • new Date() | 새로운 Date Object를 반환한다.
      • Date.now() | 현재 날짜와 시간을 number(millie seconds)으로 반환한다. 
    • Static Methods
      • Date.now() | 현재 시각을 number(millieseconds)로 변환하여 반환한다. 
      • Date.parse('yyyy-mm-ddThh:mm:ss') | 날짜 string을 number(millieseconds)로 변환하여 반환한다. 
    • Instance Methods // const now = new Date( ) 
      • get
        • now.getFullYear() || 현지시간에 따라 4자리수 연도를 반환한다. 
        • now.getMonth() || 현지시간에 따라 0-11 중 하나를 반환한다. 
        • now.getDate() || 현지시간에 따라 1-31 중 하나를 반환한다.
        • now.getDay() || 현지시간에 따라 0(일요일)-6(토요일) 중 하나를 반환한다.
      • to
        • now.toString() ||  'Tue Mar 29 2022 14:42:45 GMT+0900 (한국 표준시)'
        • now.toDateString() ||  'Tue Mar 29 2022'
        • now.toLocaleString('ko', ?options); || '2022. 3. 29. 오후 2:45:02'
          • options | {month: 'long'}

 

+) 이처럼 "dot(.)"을 이용해서 실행하는 함수들을 method라고 부른다. 즉 method는 어떤 객체 안에 내장된 함수를 말한다. 모든 method는 함수이지만, 모든 함수가 method인 것은 아니다. 

'Study > JavaScript' 카테고리의 다른 글

Map & Set  (0) 2022.03.30
Array  (0) 2022.03.29
Function & Functional Programming  (0) 2022.03.26
Control flow statement  (0) 2022.03.25
Operator  (0) 2022.03.25