ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 프로토타입(Prototype)
    frontend/javascript&web 2022. 2. 16. 08:49

    Concept By 프로토타입 (Concept By Prototype)

     

    프로토타입

    • 자바스크립트는 프로토타입 기반의 언어, 객체 원형인 프로토타입을 이용하여 새로운 객체를 생성

     

    자바스크립트는 프로토타입이라는 특수한 객체를 가지고 있으며, 이는 말그대로 다른 객체의 원형이 되는 객체 입니다. 새로운 객체를 만들어 낼 때 객체의 원형인 프로토 타입을 이용하며, 이를 통해 객체를 확장하고 객체 지향적인 프로그래밍을 할 수 있도록 도와줍니다.

     

    예시

    let fn = { // (1)
    	getName() {
    		return this.name
    	},
    	getAge() {
    		return this.age
    	}
    };
    function Person(name){ // (2)
    	let newPerson = {};
    	Object.setPrototypeOf(newPerson,fn);
    	newPerson.name = name;
    	newPerson.age = 30;
    	return newPerson;
    };
    
    let hojin = Person("류호진"); // (3)
    전역 실행 컨텍스트 전역 메모리
      fn: { getName :  fn  , getAge :  fn  } (1)
    Person:  fn  (2)
    hojin: (3)

    먼저, fn이라는 라벨을 만들고 객체를 연결해 줍니다. 그 후, Person 라벨에 함수바디를 연결해 주고, Person의 결과값을 가지는 hojin이라는 변수를 만들어 줍니다.

    let fn = { 
    	getName() {
    		return this.name
    	},
    	getAge() {
    		return this.age
    	}
    };
    function Person(name){ // (2)
    	let newPerson = {}; // (3)
    	Object.setPrototypeOf(newPerson,fn);
    	newPerson.name = name;
    	newPerson.age = 30;
    	return newPerson;
    };
    
    let hojin = Person("류호진"); // (1)
    전역 실행 컨텍스트 전역 메모리
    Person("류호진"); (1) fn: { getName :  fn  , getAge :  fn  }
    Person:  fn 
    hojin:
    함수 실행 컨텍스트 지역 메모리
    newPerson = {} (3) name : "류호진" (2)
    newPerson : {} (3)

    Person함수가 호출되면 실행 컨텍스트가 만들어지고 name이라는 매개변수에 류호진이라는 값이 할당 될 것입니다. 그 후, 함수 바디가 실행되면 newPerson에 빈 객체가 할당 됩니다.

    let fn = { 
    	getName() {
    		return this.name
    	},
    	getAge() {
    		return this.age
    	}
    };
    function Person(name){ 
    	let newPerson = {};
    	Object.setPrototypeOf(newPerson,fn); // (1)
    	newPerson.name = name; // (2)
    	newPerson.age = 30; // (2)
    	return newPerson;
    };
    
    let hojin = Person("류호진");
    전역 실행 컨텍스트 전역 메모리
    Person("류호진"); fn : { getName :  fn  , getAge :  fn  }
    Person :  fn 
    hojin :
    함수 실행 컨텍스트 지역 메모리
    Object.setPrototypeOf(newPerson,fn) name : "류호진"
    newPerson : {
        name :  "류호진",
        age : 30,
        __proto__ : fn
    }

    Object.setPrototypeOf라는 메소드를 통해 이 객체의 프로토타입을 fn 객체로 연결해 주게 됩니다. newPerson의 Prototype은 fn객체가 되는 것입니다. __proto__라는 특수속성 라벨을 이용하여 fn을 참조 하게 됩니다. 그 후, newPerson에 name속성을 만들고 값을 류호진으로 할당합니다. age도 같은 동작을 반복합니다.

    let fn = { 
    	getName() {
    		return this.name
    	},
    	getAge() {
    		return this.age
    	}
    };
    function Person(name){ 
    	let newPerson = {};
    	Object.setPrototypeOf(newPerson,fn);
    	newPerson.name = name;
    	newPerson.age = 30;
    	return newPerson; // (1)
    };
    
    let hojin = Person("류호진"); // (1)
    전역 실행 컨텍스트 전역 메모리
      fn : { getName :  fn  , getAge :  fn  }
    Person :  fn 
    hojin : {
        name : "류호진",
        age : 30,
        __proto__ : fn
    } (1)

    그리고 newPerson객체가 반환되어 hojin에 할당되고 실행컨텍스트는 종료 됩니다.

    let fn = { 
    	getName() {
    		return this.name
    	},
    	getAge() {
    		return this.age
    	}
    };
    function Person(name){ 
    	let newPerson = {};
    	Object.setPrototypeOf(newPerson,fn);
    	newPerson.name = name;
    	newPerson.age = 30;
    	return newPerson; 
    };
    
    let hojin = Person("류호진"); 
    hojin.getName(); // (1)
    전역 실행 컨텍스트 전역 메모리
    hojin.getName() fn : { getName :  fn  , getAge :  fn  }
    Person :  fn 
    hojin : {
        name : "류호진",
        age : 30,
        __proto__fn
    함수 실행 컨텍스트 지역 메모리
       

    이후, hojin.getName을 실행하게 되면 객체에 getName함수를 찾게 됩니다. 하지만 getName은 당연히 찾을 수 없을 것이고 자바스크립트 엔진은 __proto__ 라벨을 통해 프로토타입에서 찾게 됩니다. 프로토타입 내부에서 getName을 발견하면 함수실행 컨텍스트가 생성되고 그 후 이름을 반환하며 종료되게 될 것입니다.

     

    결론적으로, 프로토타입으로 객체를 만드는 방법은 객체 생성을 위한 빈 객체를 만들고, 프로토타입은 연결하고, 속성값을 할당해주고 반환하는 일련의 과정이 필요하다는 것을 알 수 있습니다.

     

    이러한 일련의 작업들을 자동으로 해주는 new 키워드를 예시와 함께 살펴보겠습니다.

    function Person(name) { // (1)
    	this.name = name;
    	this.age = 30;
    }
    Person.prototype.getName = function() () {
    	return this.name;
    }
    Person.prototype.getAge = function() () {
    	return this.age;
    }
    
    let hojin = new Person("류호진");
    hojin.getName();
    전역 실행 컨텍스트 전역 메모리
      Person :  fn  (1)
    function Person(name) {
    	this.name = name;
    	this.age = 30;
    }
    Person.prototype.getName = function() () { // (1)
    	return this.name;
    }
    Person.prototype.getAge = function() () { // (1)
    	return this.age;
    }
    
    let hojin = new Person("류호진"); // (2)
    hojin.getName();
    전역 실행 컨텍스트 전역 메모리
      Person : {
       prototype : { 
          getName :  fn  
          getAge:  fn  
       }
    } (1)
    hojin : (2)

    Person에 함수바디를 연결합니다. Person은 함수이자 객체임으로 이 객체 타입에는 프로토타입이라는 빈 객체가 있습니다. 여기에 getName과 getAge라는 속성을 추가하고 함수 바디를 연결합니다. 그리고 Person의 결과값을 가지는 hojin이라는 변수를 만듭니다.

     

    추가정보 : 자바스크립트에서 함수는 일급 객체 이다. (추후 따로 정리하겠습니다)

    function Person(name) {
    	this.name = name;
    	this.age = 30;
    }
    Person.prototype.getName = function() () {
    	return this.name;
    }
    Person.prototype.getAge = function() () {
    	return this.age;
    }
    
    let hojin = new Person("류호진"); // (1)
    hojin.getName();
    전역 실행 컨텍스트 전역 메모리
    new Person() (1) Person : {
       prototype : { 
          getName :  fn  
          getAge:  fn  
       }

    hojin :
    함수 실행 컨텍스트 지역 메모리
      name : "류호진" (1)
    this: {} (1)

    그리고 Person함수를 실행시키는데 이때 new를 붙여 실행시킵니다. 실행되었으니 name 매개변수에 류호진을 할당합니다. 아까는 Person 객체 내부에 newPerson객체를 직접 만들었습니다. new 키워드를 이용해서 생성할때는 this라는 빈객체를 만들 것입니다.

    function Person(name) {
    	this.name = name;
    	this.age = 30;
    }
    Person.prototype.getName = function() () {
    	return this.name;
    }
    Person.prototype.getAge = function() () {
    	return this.age;
    }
    
    let hojin = new Person("류호진"); // (1)
    hojin.getName();
    전역 실행 컨텍스트 전역 메모리
    new Person() Person : {
       prototype : { 
          getName :  fn  
          getAge :  fn  
       }

    hojin :
    함수 실행 컨텍스트 지역 메모리
      name : "류호진" 
    this: {
       __proto__ : {
          getName :  fn  
          getAge :  fn  
       }
    } (1)

    그리고 이 객체의 프로토타입을 Person의 Prototype으로 __proto__속성을 통해 할당해줍니다.

    function Person(name) {
    	this.name = name; // (1)
    	this.age = 30; // (1)
    }
    Person.prototype.getName = function() () {
    	return this.name;
    }
    Person.prototype.getAge = function() () {
    	return this.age;
    }
    
    let hojin = new Person("류호진");
    hojin.getName();
    전역 실행 컨텍스트 전역 메모리
    new Person() Person : {
       prototype : { 
          getName :  fn  
          getAge :  fn  
       }

    hojin : 
    함수 실행 컨텍스트 지역 메모리
      name : "류호진" 
    this: {
       name : "류호진"
       age : 30
       __proto__ : {
          getName :  fn  
          getAge :  fn  
       }
    } (1)

    그 후 this 객체에 류호진이라는 name과 30이라는 age를 할당합니다.

    전역 실행 컨텍스트 전역 메모리
      Person : {
       prototype : { 
          getName :  fn  
          getAge :  fn  
       }

    hojin : {
       name : "류호진"
       age : 30
       __proto__ : {
          getName :  fn  
          getAge :  fn  
       }
    }

    이후 hojin에는 위와 같이 값이 할당되게 됩니다. 결국 setPrototypeOf를 통해 직접 구현하였을 때와 같은 모양을 가지게 되는 것을 볼 수 있습니다.

     

    결론적으로, new의 역할은 인스턴스 생성을 위해 this라는 이름의 빈객체를 만들고, this객체에 프로토타입을 연결해준 뒤 속성값을 할당하여 반환하는 것입니다.

     

    DeepDive By 프로토타입(DeepDive By Prototype)

     

    프로토타입

    • 자바스크립트는 프로토타입 기반의 언어이며, 프로토타입의 구조는 크게 Prototype Object와 Prototype Link로 이루어져 있다. Prototype Object 내부에는 생성되었던 함수를 가르키고 있는 constructor와 Prototype Link인 __proto__로 이루어져 있다.

     

     

    우리가 Concept에서 봤던 내용의 구조는 위의 그림과 같은 구조로 이루어져 있는 것을 볼 수 있습니다. 또한 __proto__라는 특수한 속성을 통해서 프로토타입과 연결된다고 말씀드렸습니다. 여기서 __proto__는 객체가 생성될떄의 조상이었던 프로토타입을 가르킵니다. 그럼 예를 들어 하나 보겠습니다.

     

    예시

    function Person(name) {
    	this.name = name;
    	this.age = 30;
    }
    Person.prototype.getName = function() {
    	return this.name;
    }
    Person.prototype.getAge = function() {
    	return this.age;
    }
    
    let hojin = new Person("류호진");
    hojin.test;

    이러한 코드가 있다면, 가장 먼저 Person객체를 확인합니다.

     확인했는데 없다면 __proto__속성을 통해 Prototype을 확인합니다. 그 후 최상위의 Object까지 프로토타입을 탐색합니다. Object까지 탐색했을때 아무것도 못찾으면 return 값으로 undefined를 출력합니다.

    이러한 프로토타입의 구조 때문에 모든 객체는 Object의 자식이라고 불리며, 우리는 Object의 toString과 같은 속성을 사용할 수 있는 것입니다. 아래 그림과 함께 보시면 좀 더 이해가 쉬울 것이라 생각됩니다.

     

     

    결론적으로, 모든 객체의 최상위 프로토타입은 내장 Object.prototype이며 해당 최상위 객체 까지 찾지 못하면 프로토타입 체인 탐색은 종료 된다고 할 수 있습니다.

     

    우리는 오늘 프로토타입에 대해서 자세히 알아 보았습니다. 코어 자바스크립트의 내용을 점점 알아 갈수록 프레임워크 등을 이해하는데도 많은 도움이 될 것이라고 생각합니다.

     

    참고 : NHN FRONTEND CONFERENCE

            자바스크립트 완벽가이드(도서)

    반응형

    댓글

Designed by Tistory.