JS 파트 1) 4.4 : 메서드와 this

나나·2021년 9월 17일
0
post-thumbnail

객체는 실제 존재하는 개체(entity)를 표현하고자 할 때 생성된다.

따라서, 개체가 특정한 행동을 할 수 있는 것처럼

객체도 특정한 "행동"을 할 수 있다.

자바스크립트에선 객체의 프로퍼티에 함수를 할당해 객체에게 행동할 수 있는 능력을 부여한다.

메서드 만들기

객체 user에게 인사할 수 있는 능력을 부여해주자.

let user = {
  name: "Lee",
  age: 23
};

user.sayHi = function() {
  alert("안녕하세요!");
};

user.sayHi(); // 안녕하세요!

함수 표현식으로 함수를 만들고, 객체 프로퍼티 user.sayHi에 함수를 할당해주었다.

이제 객체에 할당된 함수를 호출하면 user가 인사를 한다👋🏻

이렇게 객체 프로퍼티에 할당된 함수를 메서드(method)라고 부른다.

메서드는 아래와 같이 이미 정의된 함수를 이용해서 만들 수도 있다.

let user = {
  // ...
};

// 함수 선언
function sayHi() {
  alert("안녕하세요!");
};

// 선언된 함수를 메서드로 등록
user.sayHi = sayHi;

user.sayHi(); // 안녕하세요!

💡 객체 지향 프로그래밍(Object-Oriented Programming, OOP)

객체를 사용하여 개체를 표현하는 방식이다.
OOP는 그 자체만으로도 학문의 분야를 만드는 중요한 주제이다. 올바른 개체를 선택하는 방법, 개체 사이의 상호작용을 나타내는 방법 등에 관한 의사결정은 객체 지향 설계를 기반으로 이뤄진다.

객체 지향 프로그래밍 관련 추천도서

  • 에릭 감마, 'GoF의 디자인 패턴'
  • 그래디 부치, 'UML을 활용한 객체지향 분석 설계'

메서드 단축 구문

객체 리터럴 안에 메서드를 선언할 때 사용할 수 있는 단축 문법이 있다.

// 아래 두 객체는 동일하게 동작한다.

user = {
  sayHi: function() {
    alert("Hello");
  }
};

user = {
  sayHi() { // "sayHi: function()"과 동일
    alert("Hello");
  }
};

위 코드처럼 function을 생략해도 메서드를 정의할 수 있다.

일반적인 방법과 단축 구문을 사용한 방법이 완전히 동일하진 않다. 객체 상속과 관련된 미묘한 차이가 있는데, 지금은 그냥 넘어가겠다.

메서드와 this

대부분의 메서드가 객체 프로퍼티의 값을 활용하기 때문에,
메서드는 객체에 저장된 정보에 접근할 수 있어야 한다.

위 코드 중 user.sayHi() 내부 코드에서 객체 user에 저장된 이름(name)을 이용해 인사말을 만드는 경우가 이런 경우에 속한다.

메서드 내부에서 this 키워드를 사용하면 객체에 접근할 수 있다.

여기서 this는 메서드를 호출할 때 사용된 객체를 나타낸다.

EX.

let user = {
  name: "Lee",
  age: 23,

  sayHi() {
    // 'this'는 '현재 객체'를 나타낸다.
    alert(this.name);
  }

};

user.sayHi(); // Lee

user.sayHi()가 실행되는 동안에 thisuser를 나타낸다.

this를 사용하지 않고 외부 변수를 참조해 객체에 접근하는 것도 가능하다.

let user = {
  name: "Lee",
  age: 23,

  sayHi() {
    alert(user.name); // 'this' 대신 'user'를 이용
  }
};

❗ 그런데 이렇게 외부 변수를 사용해 객체를 참조하면 예상치 못한 에러가 발생할 수 있다.

user를 복사해 다른 변수에 할당(admin = user)하고, user는 전혀 다른 값으로 덮어썼다면, sayHi()는 원치 않는 값(null)을 참조하게 될 것이다.

EX.

let user = {
  name: "John",
  age: 30,

  sayHi() {
    alert( user.name ); // Error: Cannot read property 'name' of null
  }

};


let admin = user;
user = null; 

admin.sayHi(); // sayHi()가 엉뚱한 객체를 참고하면서 에러 발생

alert 함수가 user.name 대신 this.name을 인수로 받았다면 에러가 발생하지 않았을 것이다.

자유로운 this

자바스크립트의 this는 다른 프로그래밍 언어의 this와 동작 방식이 다르다.

자바스크립트에선 모든 함수에 this를 사용할 수 있다.

this값은 context에 따라 달라지기 때문에 런타임에 결정된다. 메서드가 어디서 정의되었는지에 상관없이 this는 ‘점 앞의’ 객체가 무엇인가에 따라 ‘자유롭게’ 결정된다.

이렇게 this가 런타임에 결정되면 함수(메서드)를 하나만 만들어 여러 객체에서 재사용할 수 있다는 것은 장점이지만, 이런 유연함이 실수로 이어질 수 있다는 단점이 있다. 따라서 개발자가 this의 동작 방식을 충분히 이해하고 장점을 취하면서 실수를 피해야한다.

동일한 함수라도 다른 객체에서 호출했다면 'this'가 참조하는 값이 달라진다.

let user = { name: "John" };
let admin = { name: "Admin" };

function sayHi() {
  alert( this.name );
}

// 별개의 객체에서 동일한 함수를 사용함
user.f = sayHi;
admin.f = sayHi;

// 'this'는 '점(.) 앞의' 객체를 참조하기 때문에
// this 값이 달라짐
user.f(); // John  (this == user)
admin.f(); // Admin  (this == admin)

admin['f'](); // Admin (점과 대괄호는 동일하게 동작함)

💡 객체 없이 호출하기: this == undefined

객체가 없어도 함수를 호출할 수 있다.위와 같은 코드를 엄격 모드에서 실행하면, this에는 undefined가 할당된다. 따라서 this.name으로 name에 접근하려고 하면 당연히 에러가 발생한다.

그런데 엄격 모드가 아닐 경우,

this는 전역 객체를 참조한다. 브라우저 환경에선 window라는 전역 객체를 참조한다. 이런 동작 차이가 엄격 모드가 도입된 배경이기도 하다.
❗ 이런 식의 코드는 대개 실수로 작성된 경우가 많다. 함수 본문에 this가 사용됐다면, 객체 context 내에서 함수를 호출할 거라 생각하면 된다.

this가 없는 화살표 함수

화살표 함수는 일반 함수와는 달리 "고유한" this를 가지지 않는다.

화살표 함수에서 this를 참조하면, 화살표 함수가 아닌 '평범한' 외부 함수에서 this값을 가져온다.

아래 예시를 보며 이해해보자.

EX.

let user = {
  firstName: "나나이유",
  sayHi() {
    let arrow = () => alert(this.firstName); 
    // 함수 arrow()의 this는 외부 함수 user.sayHi()의 this
    arrow();
  }
};

user.sayHi(); // 나나이유

별개의 this가 만들어지는 것보다, 외부 context에 있는 this를 이용하고 싶은 경우 화살표 함수가 유용하다.

이 글은 https://ko.javascript.info/ 를 참고하여 작성하였습니다.

profile
코린이의 둥당둥당 개발일지

0개의 댓글

관련 채용 정보