Leeyanggoo
[JS] 객체생성자 / 프로토타입 / 객체리터럴 함수의 차이?! 본문
요번에 공부하면서 정말이지 헷갈리고 이해하기 어려웠던 세 가지 함수 유형에 대해 알아보려고 합니다!
이해를 돕기 위해 모두 같은 결과를 도출하는 예제로 작성해보겠습니다!
객체생성자 함수
function Func(num, name, word){
this.num = num;
this.name = name;
this.word = word;
this.result = function(){
document.write(this.num + ". " + this.name + "가 " + this.word + "되었읍디다.<br>");
} //객체의 메서드라고 함.
}
//인스턴스 생성 new
const info1 = new Func(1, "함수", "실행");
const info2 = new Func(2, "자바스크립트", "실행");
const info3 = new Func(3, "리액트", "실행");
info1.result();
info2.result();
info3.result();
먼저 가장 첫 번째로 쓴 객체생성자 함수가 어떤 함수인지 알아보겠습니다.
자바스크립트의 'this'는 간단히 말해 "누가 나 불렀음?"이라고 생각하시면 됩니다.
즉 함수를 호출할 때 어떻게 호출했는지에 따라서 this와 묶이는(바인딩, 혹은 상속받는) 객체가 결정된다는 뜻입니다.
객체생성자 함수는 그 이름을 살펴보면 조금 이해하기 쉽습니다.
말 그대로 객체를 생성(인스턴스 생성) 하는 함수.
this는 생성한 객체로 어떻게 호출할지 결정.
즉 객체생성자 함수는 객체를 만들어서 함수를 정의하는 함수라고 보시면 됩니다.
우리는 생성한 객체(인스턴스)에 어떤 데이터를 넣느냐에 따라 this를 통해 함수를 정의합니다.
우리가 객체를 만들고 그 안에 데이터를 쭉 넣는 것보다 함수가 어떻게 생겼는지 정의하고, 밖에서 새로운 객체를 만들어서 그 데이터를 입력하는 것이 여러 장점을 갖는다는 것입니다.
이렇게 객체 생성자를 쓰게 되면 객체를 생성하는 코드를 간결하고 직관적으로 작성할 수 있습니다.
또한 각각의 객체가 독립적이기 때문에 충돌을 방지하고 재사용하기에도 편합니다.
프로토타입 함수
function Func(num, name, word){
this.num = num;
this.name = name;
this.word = word;
this.result = function(){
document.write(this.num + ". " + this.name + "가 " + this.word + "되었읍디다.<br>");
this.result = function(){
document.write(this.num + ". " + this.name + "가 " + this.word + "되었읍디다.<br>");
this.result = function(){
document.write(this.num + ". " + this.name + "가 " + this.word + "되었읍디다.<br>");
this.result = function(){
document.write(this.num + ". " + this.name + "가 " + this.word + "되었읍디다.<br>");
this.result = function(){
document.write(this.num + ". " + this.name + "가 " + this.word + "되었읍디다.<br>");
} //객체의 메서드가 많은 경우
}
//인스턴스 생성 new
const info1 = new Func(1, "함수", "실행");
const info2 = new Func(2, "자바스크립트", "실행");
const info3 = new Func(3, "리액트", "실행");
const info1 = new Func(1, "함수", "실행");
const info2 = new Func(2, "자바스크립트", "실행");
const info3 = new Func(3, "리액트", "실행");
const info1 = new Func(1, "함수", "실행");
const info2 = new Func(2, "자바스크립트", "실행");
const info3 = new Func(3, "리액트", "실행");
const info1 = new Func(1, "함수", "실행");
const info2 = new Func(2, "자바스크립트", "실행");
const info3 = new Func(3, "리액트", "실행");const info1 = new Func(1, "함수", "실행");
const info2 = new Func(2, "자바스크립트", "실행");
const info3 = new Func(3, "리액트", "실행");
info1.result();
info2.result();
info3.result();
만약 우리가 객체 안에서 다른 함수를 추가해야 하거나, 인스턴스 생성을 더 많이 해야 하는 경우를 가정해볼까요?
이런 경우 우리는 객체 생성(인스턴스 생성)마다 함수 "Func"가 실행이 되면서 그 안의 객체의 메서드("this.result")도 모두 실행이 될 것입니다.
하지만 우리가 모든 메서드(내부에 있는 모든 result)가 필요한 것이 아니라면?
일부만 실행하고 싶거나 불필요한 실행이 속해 있다면 다른 메서드의 실행은 크나큰 메모리의 낭비라고 볼 수 있습니다.
그래서 더욱 효율적으로 객체를 호출하고 활용하기 위해 나온 것이 프로토타입 함수입니다.
function Func(num, name, word){
this.num = num;
this.name = name;
this.word = word;
}
//프로토타입 생성 // 지역변수인 this를 밖에서 쓸 수 있게 해줌
Func.prototype.result = function(){
document.write(this.num + ". " + this.name + "가 " + this.word + "되었읍디다.");
} //바깥으로 나온 메서드
const info1 = new Func(1, "함수", "실행");
const info2 = new Func(2, "자바스크립트", "실행");
const info3 = new Func(3, "리액트", "실행");
info1.result();
info2.result();
info3.result();
프로토타입 함수는 메서드(this.result)가 바깥으로 나온 모양이죠?
이렇게 프로토타입 함수는 객체의 호출을 함수 내에서 진행하지 않기 때문에 불필요한 메모리를 낭비하지 않습니다.
function Func(num, name, word){this.num=num; this.name=name; this.word=word;}의 함수를 정의하는 부분만 남기고 나머지 실행은 프로토타입 함수를 이용해 지역변수인 this를 밖에서 호출하는 것입니다.
또한 객체생성자 함수는 새로운 메서드(함수)를 만들기 위해선 해당 객체 안에서만 가능하지만 프로토타입 함수를 이용한다면 객체가 생성된 뒤에도 함수의 추가가 자유롭기 때문에 더욱 유동적으로 활용할 수 있습니다.
객체리터럴 함수
function Func(num, name, word){
this.num = num;
this.name = name;
this.word = word;
}
//프로토타입 생성 // 지역변수인 this를 밖에서 쓸 수 있게 해줌
Func.prototype.result = function(){
document.write(this.num + ". " + this.name + "가 " + this.word + "되었읍디다.");
}
Func.prototype.result = function(){
document.write(this.num + ". " + this.name + "를 " + this.word + "되었읍디다.");
}
Func.prototype.result = function(){
document.write(this.num + ". " + this.name + "을 " + this.word + "되었읍디다.");
}
Func.prototype.result = function(){
document.write(this.num + ". " + this.name + "이 " + this.word + "되었읍디다.");
}
Func.prototype.result = function(){
document.write(this.num + ". " + this.name + "에 " + this.word + "되었읍디다.");
}
Func.prototype.result = function(){
document.write(this.num + ". " + this.name + "에서 " + this.word + "되었읍디다.");
}
const info1 = new Func(1, "함수", "실행");
const info2 = new Func(2, "자바스크립트", "실행");
const info3 = new Func(3, "리액트", "실행");
const info1 = new Func(1, "함수", "실행");
const info2 = new Func(2, "자바스크립트", "실행");
const info3 = new Func(3, "리액트", "실행");
const info1 = new Func(1, "함수", "실행");
const info2 = new Func(2, "자바스크립트", "실행");
const info3 = new Func(3, "리액트", "실행");
const info1 = new Func(1, "함수", "실행");
const info2 = new Func(2, "자바스크립트", "실행");
const info3 = new Func(3, "리액트", "실행");
info1.result();
info2.result();
info3.result();
우리는 항상 함수를 대할 때 가정을 해야 합니다.
만약 이 프로토타입 함수가 엄~청 늘어난다면?
우리가 만드려는 페이지의 기능이 많아져서 메서드와 객체가 늘어났다면!?
프로토타입은 객체생성자 함수에 비해 효율적으로 메모리와 객체를 관리할 수 있다는 장점을 가졌지만,
그 수가 많아질수록 코드의 가독성이 나빠진다는 단점을 가지고 있습니다.
이런 경우 우리는 객체리터럴 형식으로 메서드를 정의한다고 하는 객체리터럴 함수를 사용할 수 있습니다.
function func(num, name, com){
this.num = num;
this.name = name;
this.com = com;
}
func.prototype = {
result1: function(){
document.write(`${this.num}. ${this.name}가 ${this.com}되었습니다.<br>`);
},
result2: function(){
document.write(`${this.num}. ${this.name}가 ${this.com}되었습니다.<br>`);
},
result3: function(){
document.write(`${this.num}. ${this.name}가 ${this.com}되었습니다.<br>`);
}
}
//인스턴스
const info1 = new func("102", "함수", "실행");
const info2 = new func("202", "자바스크립트", "실행");
const info3 = new func("302", "리액트", "실행");
//실행문
info1.result1();
info2.result2();
info3.result3();
어떻게 보면 객체생성자 함수에서 메서드가 함수 안에 있던 모습과 비슷해 보일지도 모릅니다.
그러나 객체리터럴 함수는 메서드를 객체로 묶는다고 생각하시면 됩니다.
프로토타입 함수 같은 메서드뿐만 아니라 다른 함수들도 객체화해서 묶어놓음으로써 다양한 메서드를 직관적으로 정의할 수 있는 것입니다.