Javascript/[인프런] 자바스크립트 중고급
[자바스크립트 중고급] 5. function instance
minha62
2022. 2. 18. 04:16
function 인스턴스 기준
function Book(point){
this.point = point;
};
Book.prototype.getPoint = function(){
return this.point + 200;
};
var obj = new Book(100);
obj.getPoint();
- function 구분
- 빌트인 Function 오브젝트
- function 오브젝트: function 키워드로 생성
- function 인스턴스: new 연산자로 생성
- function 오브젝트도 인스턴스
- 빌트인 Function 오브젝트로 생성하기 때문
- 성격적으로는 인스턴스이지만
- new 연산자로 생성한 인스턴스와 구분하기 위해 강좌에서는 function 오브젝트로 표기
- new 연산자로 생성하는 인스턴스는
- 일반적으로 prototype에 프로퍼티를 작성
function 인스턴스 생성
function Book(point){
this.point = point;
};
Book.prototype.getPoint = function(){
return this.point + 200;
};
var obj = new Book(100);
log(obj.point);
log(obj.getPoint());
// 100
// 300
위의 코드는 function 인스턴스를 생성하는 전형적인 형태
인스턴스 생성 순서, 방법
- function Book(point){...}
- Book 오브젝트를 생성
- Book.prototype이 만들어짐
- Book.prototype.getPoint = function(){}
- Book.prototype에 getPoint를 연결하고 function(){}을 할당
- Book.prototype이 오브젝트이므로 프로퍼티를 연결할 수 있음
- var obj = new Book(100);
- Book()을 실행하며 인스턴스를 생성하고 생성한 인스턴스에 point 값을 설정
- Book.prototype에 연결된 프로퍼티를 생성한 인스턴스에 할당
- console.log(obj.point);
- obj 인스턴스에서 프로퍼티 이름으로 값을 구해 출력
- console.log(obj.getPoint());
- obj 인스턴스의 메소드를 호출
- return this.point + 200;에서
- this가 obj 인스턴스를 참조
- 강좌의 함수/메소드 사용 기준
- Book(): 함수
- getPoint(): 메소드, prototype에 연결
생성자 함수
- new 연산자와 함께 인스턴스를 생성하는 함수
- new Book()에서 Book()이 생성자 함수
- new 연산자
- 인스턴스 생성을 제어
- 생성자 함수 호출
- 생성자 함수
- 인스턴스 생성, 반환
- 인스턴스에 초기값 설정
- 코딩 관례로 생성자 함수의 첫 문자는 대문자
- new Number(), new Array(), new Book()
생성자 함수 실행 과정
function Book(point){
this.point = point;
};
Book.prototype.getPoint = function(){
return this.point;
};
var obj = new Book(10);
new 연산자로 인스턴스 생성을 제어하고, 생성자 함수인 Book()으로 인스턴스를 생성하여 반환
new와 생성자 함수 실행 과정
- 엔진이 new 연산자를 만나면
- function의 [[Construct]]를 호출하면서 파라미터 값으로 10을 넘겨줌
- function 오브젝트를 생성할 때
- Book() 함수 전체를 참조하도록 [[Construct]]에 설정함
- [[Construct]]에서 인스턴스를 생성하여 반환
- 반환된 인스턴스를 new 연산자가 받아
- new 연산자를 호출한 곳으로 반환
- new라는 뉘앙스로 인해
- new 연산자가 인스턴스를 생성하는 것으로 생각할 수 있지만
- function 오브젝트의 [[Construct]]가 인스턴스를 생성
- 그래서 Book()이 생성자 함수
인스턴스 생성 과정
function Book(point){
this.point = point;
};
Book.prototype.getPoint = function(){
return this.point;
};
var bookObj = new Book(10);
Book 인스턴스: {
point: 10,
__proto__ = {
constructor: Book,
getPoint: function(){},
__proto__: Object
}
}
- new Book(10) 실행
- Book 오브젝트의 [[Construct]] 호출
- 파라미터 값을 [[Construct]]로 넘겨줌
- 빈 Object를 생성
- 이것이 인스턴스
- 지금은 빈 오브젝트{ }이며 이제부터 하나씩 채워감
- 오브젝트에 내부 처리용 프로퍼티를 설정
- 공통 프로퍼티와 선택적 프로퍼티
- 오브젝트의 [[Class]]에 "Object" 설정
- 따라서 생서한 인스턴스 타입은 Object
- Book.prototype에 연결된 프로퍼티(메소드)를
- 생성한 인스턴스의 [[Prototype]]에 설정
- constructor도 같이 설정됨
constructor 프로퍼티
Book function 오브젝트: {
prototype: {
constructor: Book
}
}
- 생성하는 function 오브젝트를 참조
- function 오브젝트를 생성할 때 설정
- prototype에 연결되어 있음
- 개인 경험
- constructor가 없더라도 인스턴스가 생성됨
- 하지만, 필요하지 않다는 의미는 아님
- ES5: constructor 변경 불가
- 생성자를 활용할 수 없음
- ES6: constructor 변경 가능
- 활용성 높음
constructor 비교
var Book = function(){};
var result = Book === Book.prototype.constructor;
log("1:", result);
var obj = new Book();
log("2:", Book === obj.constructor);
log("3:", typeof Book);
log("4:", typeof obj);
// 1:true
// 2:true
// 3:function
// 4:object
- Book === Book.prototype.constructor;
- [실행결과] 1번에 true가 출력된 것은
- Book 오브젝트와 Book.prototype.constructor가 타입까지 같다는 뜻
- Book 오브젝트를 생성할 때 Book.prototype.constructor가 Book 오브젝트를 참조하기 때문
- Book === obj.constructor;
- obj의 constructor가 Book 오브젝트를 참조하므로
- [실행결과] 2번에 true가 출력됨
- typeof Book;
- Book 오브젝트의 타입은 function
- typeof obj;
- obj 인스턴스 타입은 object
- function 오브젝트를 인스턴스로 생성했더니
- object로 타입이 변경됨
- 이것은 [[Construct]]가 실행될 때 생성한 오브젝트의 [[Class]]에 'Object'를 설정하기 때문
- 오브젝트 타입이 바뀐다는 것은
- 오브젝트 성격과 목적이 바뀐 것을 뜻함
- 다른 관점에서 접근해야 함
prototype 오브젝트 목적
- prototype 확장
- prototype에 프로퍼티를 연결하여 prototype 확장
- Book.prototype.getPoint = function(){}
- 프로퍼티 공유
- 생성한 인스턴스에서 원본 prototype의 프로퍼티 공유
- var obj = new Book(123); obj.getPoint;
- 인스턴스 상속(Inheritance)
- function 인스턴스를 연결하여 상속
- Point.prototype = new Book();
인스턴스 상속
- 인스턴스 상속 방법
- prototype에 연결된 프로퍼티로 인스턴스를 생성하여 상속받을 prototype에 연결
- 그래서 prototype-based 상속이라고도 함
function Book(title){
this.title = title;
};
Book.prototype.getTitle = function(){
return this.title;
};
function Point(title){
Book.call(this, title);
};
Point.prototype = Object.create(Book.prototype, {});
var obj = new Point("자바스크립트");
log(obj.getTitle());
// 자바스크립트
- JS에서 prototype은 상속보다
- 프로퍼티 연결이 의미가 더 큼
- 인스턴스 연결도 프로퍼티 연결의 하나
- ES5 상속은 OOP의 상속 기능 부족
- ES6의 Class로 상속 사용
class Book{
constructor(title){
this.title = title;
};
getTitle(){
return this.title;
}
};
class Point extends Book{
constructor(title){
super(title);
};
};
const obj = new Point("자바스크립트");
log(obj.getTitle());
// 자바스크립트
prototype 확장 방법
- prototype에 프로퍼티를 연결하여 작성
- prototype.name = value 형태
- name에 프로퍼티 이름 작성
- value에 JS 데이터 타입 작성
- 일반적으로 function을 사용
- prototype에 null을 설정하면 확장 불가
프로퍼티 연결 고려사항
- prototype에 연결할 프로퍼티가 많을 때
- Book.prototype.name1, 2, 3 ~ N 형태는 Book.prototype을 반복해서 작성해야 하므로 번거로움
- Book.prototype = {name1: value, ...} 형태로 작성
- constructor가 지워지는 문제와 대책
- {name1: value, ...} 형태로 설정한 후
- prototype에 constructor를 다시 연결
constructor 연결
function Book(){};
Book.prototype = {
constructor: Book,
setPoint: function(){}
};
var obj = new Book();
log(obj.constructor);
// function Book(){}
- 오브젝트 리터럴{}을 사용하여
- 프로퍼티를 연결할 때에는
- constructor가 지워지는 것을 고려해야 함
- constructor가 없어도 인스턴스가 생성되지만
- constructor가 연결된 것이 정상이므로
- 코드처럼 constructor에 Book function을 할당
prototype 확장과 인스턴스 형태
function Book(point){
this.point = point;
};
Book.prototype.getPoint = function(){
return this.point;
};
var obj = new Book(100);
obj.getPoint();
obj: {
point: 100,
__proto__ = {
constructor: Book,
getPoint: function(){},
__proto__: Object
}
}
prototype 확장
- function Book(point){};
- Book 오브젝트 생성
- Book.prototype.getPoint = function(){}
- Book.prototype에 getPoint 메소드 연결
- var obj = new Book(100);
- 인스턴스를 생성하여 obj에 할당
- obj.getPoint()
- obj 인스턴스의 getPoint() 호출
- 인스턴스를 생성하면
- prototype에 연결된 메소드를
- 인스턴스.메소드이름() 형태로 호출
this와 prototype
this로 인스턴스 참조
- this로 메소드를 호출한 인스턴스 참조
- var obj = new Book();
- obj.get() 형태에서 this로 obj 참조
- 인스턴스에서 메소드 호출 방법
- prototype에 연결된 프로퍼티가 __proto__에 설정되며
- 인스턴스 프로퍼티가 됨
- this.prototype.setPoint() 형태가 아닌 this.setPoint() 형태로 호출
this와 prototype
function Book(){
log("1:", this.point);
};
Book.prototype.getPoint = function(){
this.setPoint();
log("2:", this.point);
};
Book.prototype.setPoint = function(){
this.point = 100;
};
var obj = new Book();
obj.getPoint();
// 1:undefined
// 2:100
- console.log("1:", this.point);
- 생성자 함수에서 this는 생성하는 인스턴스 참조
- 생성하는 인스턴스에 point 프로퍼티가 없더라도 에러가 나지 않고 undefined 반환
- obj.getPoint();
- this가 메소드를 호출한 인스턴스 참조
- 즉, 메소드 앞에 작성한 인스턴스 참조
- this.setPoint();
- this가 인스턴스 참조하며
- 인스턴스에 있는 setPoint() 호출
- this.point = 100;
- this가 인스턴스를 참조
- 인스턴스의 point 프로퍼티에 100을 할당
prototype 메소드 직접 호출
function Book(point){
this.point = point;
};
Book.prototype.getPoint = function(){
return this.point;
};
var obj = new Book(100);
log(obj.getPoint());
log(Book.prototype.getPoint());
// 100
// undefined
- Book.prototype.getPoint();
- 인스턴스를 생성하지 않고 직접 메소드 호출
- Book.prototype을
- getPoint()에서 this로 참조
- obj 인스턴스에는 point가 있지만
- Book.prototype에 point가 없으므로 undefined를 반환
- 인스턴스를 생성하여 메소드를 호출하는 것과 직접 prototype을 작성하여 호출하는 것의 차이
prototype 프로퍼티 공유 시점
- 사용하는 시점에 prototype의 프로퍼티 공유
- prototype의 프로퍼티로 인스턴스를 생성하지만
- 인스턴스의 프로퍼티는 원본 prototype의 프로퍼티를 참조
- 복사하여 인스턴스에 갖고 있는 개념이 아님
- 인스턴스의 메소드를 호출하면
- 원본 prototype의 메소드를 호출
- 원본 prototype에 메소들르 추가하면
- 생성된 모든 인스턴스에서 추가한 메소드 사용 가능
- 원본 prototype의 메소드를 호출하기 때문
function Book(){
this.point = 100;
};
var obj = new Book();
log(obj.getPoint);
Book.prototype.getPoint = function(){
return this.point;
};
var result = obj.getPont();
log(result);
// undefined
// 100
- var obj = new Book();
- 인스턴스를 생성하여 obj에 할당
- console.log(obj.getPoint);
- obj 인스턴스에 getPoint()가 없음
- Book.prototype.getPoint = function(){return this.point;};
- Book.prototype에 getPoint() 추가
- 앞에서 생성한 obj 인스턴스에서 getPoint()를 사용할 수 있음
- var result = obj.getPoint();
- 인스턴스를 생성할 때는 obj에 getPoint가 없었지만
- getPoint()를 호출하기 전에 Book.prototype에 getPoint를 추가했으므로 호출할 수 있음
- return this.point;
- 추가하더라도 this가 인스턴스를 참조
- 이런 특징을 활용하여
- 상황(필요)에 따라 메소드를 추가
- 역동적인 프로그램 개발 가능
인스턴스 프로퍼티
obj 인스턴스 = {
point: 100,
getPoint: function(){},
__proto__: {
getPoint: function(){}
}
}
- prototype에 연결된 프로퍼티도
- 인스턴스 프로퍼티가 됨
- 직접 인스턴스에 연결된 프로퍼티와 차이 있음
- 인스턴스의 프로퍼티를
- prototype으로 만든 인스턴스 프로퍼티보다 먼저 사용
- 인스턴스마다 값을 다르게 가질 수 있음
- 인스턴스를 사용하는 중요한 목적
인스턴스 프로퍼티 우선 사용
function Book(point){
this.point = point;
};
Book.prototype.getPoint = function(){
return 100;
};
var obj = new Book(200);
obj getPoint = function(){
return this.point;
};
log(obj.getPoint());
// 200
- Book.prototype.getPoint = function(){return 100;};
- prototype에 getPoint를 연결
- 인스턴스의 getPoint()를 호출하면 100 반환
- obj.getPoint = function(){return this.point;};
- 생성한 인스턴스에 getPoint를 연결
- 함수가 호출되면 200 반환
- obj 인스턴스 구성 형태
obj 인스턴스 = {
getPoint: function(){return this.point;},
__proto__: {
getPoint: function(){return 100;}
}
}
4. obj.getPoint();
- obj 인스턴스의 getPoint() 호출
- prototype의 getPoint()가 호출되지 않고 인스턴스의 getPoint()가 호출됨
- 인스턴스에 연결한 프로퍼티를 먼저 사용하기 때문
5. 인스턴스 프로퍼티는 공유되지 않음
6. Class 접근
- 설계가 중요
- OOP 개념 이해 필요