객체는 실제 존재하는 개체(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
을 생략해도 메서드를 정의할 수 있다.
일반적인 방법과 단축 구문을 사용한 방법이 완전히 동일하진 않다. 객체 상속과 관련된 미묘한 차이가 있는데, 지금은 그냥 넘어가겠다.
대부분의 메서드가 객체 프로퍼티의 값을 활용하기 때문에,
메서드는 객체에 저장된 정보에 접근할 수 있어야 한다.
위 코드 중 user.sayHi()
내부 코드에서 객체 user
에 저장된 이름(name)을 이용해 인사말을 만드는 경우가 이런 경우에 속한다.
메서드 내부에서 this 키워드를 사용하면 객체에 접근할 수 있다.
여기서 this
는 메서드를 호출할 때 사용된 객체를 나타낸다.
EX.
let user = {
name: "Lee",
age: 23,
sayHi() {
// 'this'는 '현재 객체'를 나타낸다.
alert(this.name);
}
};
user.sayHi(); // Lee
user.sayHi()
가 실행되는 동안에 this
는 user
를 나타낸다.
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
값은 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
값을 가져온다.
아래 예시를 보며 이해해보자.
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/ 를 참고하여 작성하였습니다.