본문 바로가기

JavaScript

Object

자바스크립트에서 숫자, 문자, 참/거짓 등 기본 데이터 타입을 제외한 모든 타입은 Object, 객체 타입이다. 

 

const person1 = {
  name: "잉여인간",
  age: 28,
  introduce: function () {
    console.log("안녕! 나는 잉여인간이야. 나이는 28이고!");
  },
};

이런 형식으로 중괄호를 사용해서 만들 수 있다. 

여기서 두 번째 사람을 만들고 싶다면 아래와 같이 만들 수 있다. 

const person1 = {
  name: "잉여인간",
  age: 28,
  introduce: function () {
    console.log("안녕! 나는 잉여인간이야. 나이는 28이고!");
  },
};

const person2 = {
  name: "열심인간",
  age: 30,
  introduce: function () {
    console.log("안녕! 나는 열심인간이야. 나이는 30이고!");
  },
};

동일하게 사용되는 값 하나만 중복되도 기분이 찝찝하고 화가나는 개발자로써 불편한 점이 한 둘이 아니다. 

첫 번째로 introduce는 name과 age가 있는데 굳이 문자로 따로 작성해주고 있다. 

이미 있는 값이면 해당 값을 활용해서 만들 수 있지 않을까? 

 

두 번째로 동일한 유형의 코드 person1과 person2가 반복되고 있다. 

정말 보기만 해도 이가 갈리고 열이 나는 코드이다. 이것을 하나씩 바꿔보자. 

 

내부 값 사용하기 

우선 첫 번째 문제를 해결해보자. 

introduce 함수는 이미 같은 객체 내에 name과 age가 있고 이것을 활용해서 만들 수 있다. 

const person1 = {
  name: "잉여인간",
  age: 28,
  introduce: function () {
    console.log(`안녕! 나는 ${name}이야. 나이는 ${age}이고!`);
  },
};

const person2 = {
  name: "열심인간",
  age: 30,
  introduce: function () {
    console.log(`안녕! 나는 ${name}이야. 나이는 ${age}이고!`);
  },
};

person1.introduce();

단순하게 introduce 함수에서 name과 age를 가지고 오면 될까? 

age가 없다는 오류에서 바로 문제가 발생한다. 

당연하게도 age라는 변수를 어디에서도 선언하지 않았기 때문이다. 

 

그런데 왜 name은 문제가 없고 age에서 문제가 발생할까? 

name도 변수로 선언하진 않았지만 window의 전역 객체에 name이라는 변수가 존재한다. 

 

그러므로 name으로 사용된 변수가 없어서 window의 name을 사용해버린 것이다. 

그렇다면 객체에서 변수가 아닌 자기 자신의 값을 사용하는 방법은 뭘까? 

const person1 = {
  name: "잉여인간",
  age: 28,
  introduce: function () {
    console.log(`안녕! 나는 ${this.name}이야. 나이는 ${this.age}이고!`);
  },
};

const person2 = {
  name: "열심인간",
  age: 30,
  introduce: function () {
    console.log(`안녕! 나는 ${this.name}이야. 나이는 ${this.age}이고!`);
  },
};

person1.introduce();

this 객체를 사용하면 된다. 

this는 호출한 주체를 나타낸다. person1의 introduce에서 this가 호출되었기 때문에 person1의 값에서 찾아낸다. 

const person1 = {
  name: "잉여인간",
  age: 28,
  introduce: function () {
    console.log(`안녕! 나는 ${this.name}이야. 나이는 ${this.age}이고!`);
  },
  introduce1: () => {
    console.log(`안녕! 나는 ${this.name}이야. 나이는 ${this.age}이고!`);
  },
};

화살표 함수에서 this를 호출한다면 person1이 아닌 최상위 영역인 window를 호출하게 된다. 

사용할 때 호출하는 곳을 잘 확인해서 상황에 맞게 사용해야한다. 

 

※ this 

객체에서 function 함수와 arrow function을 비교했을 때 차이가 있었다. 

마찬가지로 여러가지 경우에서 function과 arrow function은 차이가 있다. 

 

이벤트 함수 

const function1 = () => {
  console.log(this);
};

function function2() {
  console.log(this);
}

document.querySelector(".fun1").addEventListener("click", function1);
document.querySelector(".fun2").addEventListener("click", function2);

이벤트 함수에서 function의 this는 본인을 호출한 요소의 this를 나타낸다. 

즉, function2는 fun2 class를 가지고 있는 Element를 나타낸다. 

 

하지만 arrow function의 this는 여전히 window를 나타낸다. 

 

일반 호출

const function1 = () => {
  console.log(this);
};

function function2() {
  console.log(this);
}

function1();
function2();

일반적인 함수 호출에서는 동일한 결과를 나타내는데, 이유는 function에서는 호출의 주체인 window가 

arrow function은 최상위 window가 여전히 호출되는 것이다. 

 

즉, 동일한 결과를 나타내지만 실제 호출되는 이유는 다르다. 

핵심은 function 함수는 호출의 주체를 this에 나타내고 arrow function은 최상위 window를 나타낸다. 

 

생성자를 사용해서 반복 막기

name과 age는 객체마다 다르기 때문에 매번 만드는게 이해할 수 있겠지만 introduce는 동일한 코드가 반복된다. 

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.introduce = function () {
    console.log(`안녕! 나는 ${this.name}이야. 나이는 ${this.age}이고!`);
  };
}

const person1 = new Person("잉여인간", 28);

person1.introduce();

생성자 함수 Person을 사용해서 재사용할 수 있다. 

new 키워드를 사용하면 함수를 생성자로써 호출이 된다. 그렇게 되면 this는 함수 자체의 객체를 가리키게 되는 것이고 키워드가 없이 사용되는 경우는 오류를 발생한다. 

const person1 = new Person("잉여인간", 28);
const person2 = Person("잉여인간2", 30);

person1.introduce();
person2.introduce();

생성자 함수로 만들어진 person1을 인스턴스라고 한다. 

 

이렇게 생성자 함수를 만들어서 끝낼 수 있겠지만 name과 age는 분명 객체마다 다르다. 하지만 introduce는 굳이 객체마다 다른 함수일 필요는 없다. 

내부적으로 전부 this 객체의 값을 사용하기 때문에 name과 age만 다르다면 같은 함수라도 원하는 동작을 할 것이다. 

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.introduce = function () {
    console.log(`안녕! 나는 ${this.name}이야. 나이는 ${this.age}이고!`);
  };
}

하지만 위 코드에서의 this.introduce까지 new Person을 한 객체가 모두 개별적으로 가지고 있다. 

 

즉, 위 코드의 introduce는 개별적으로 가지고 있기 때문에 불필요하게 메모리를 차지하고 있다. 

메모리가 낭비되는 것이다. 

 

공통으로 사용하는 메서드는 공유를 하는 형식으로 수정을 할 수 있다. 

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.introduce = function () {
  console.log(`안녕! 나는 ${this.name}이야. 나이는 ${this.age}이고!`);
};

const person1 = new Person("잉여인간", 28);
const person2 = new Person("잉여인간2", 30);

person1.introduce();
person2.introduce();

prototype 객체를 사용해서 선언하면 person1과 person2의 introduce는 서로 공유되고 있다. 

메모리 상에도 Person 객체가 늘어나도 introduce가 늘어나지는 않는다. 

 

시작 부분에서부터 굳이 함수로 만들 필요가 있는지 생각하는 사람이 있을 것이다. 

맞다. 굳이 함수일 필요가 없이 class를 사용해서 만들어줄 수 있다. 

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  introduce() {
    console.log(`안녕! 나는 ${this.name}이야. 나이는 ${this.age}이고!`);
  }
}

const person3 = new Person("잉여인간3", 32);

person3.introduce();
반응형

'JavaScript' 카테고리의 다른 글

스크롤 위치에 따른 오브젝트 조작  (1) 2024.09.29
얕은 복사 & 깊은 복사  (3) 2024.09.25
호이스팅  (1) 2024.08.21
함수 스코프, 블록 스코프  (1) 2024.08.14
JavaScript defer & async  (2) 2024.06.27