호다닥

초보자를 위한 Javascript: 'new' 예약어 본문

Javascript

초보자를 위한 Javascript: 'new' 예약어

3jun 2018. 8. 2. 08:01

JavaScript For Beginners: the 'new' operator

출처 : codeburst.io, Brandon Morelli

해당 내용은 Brandon Morelli의 article을 개인적으로 번역한 내용이며, 잘못 번역된 부분이 있을 수 있습니다. 원문은 위에 적힌 주소에서 확인하실 수 있습니다.

 

4가지 법칙

new 예악어가 무엇인지 이해하는 것은 new 예악어를 이해하는 가장 간단한 방법이다. 

new 예악어를 사용할 때, 4가지의 일들이 발생한다.

  1. 새로운 빈 객체를 만들어낸다.
  2. this를 새로 만들어진 객체에 bind한다.
  3. 새로 만들어진 객체에 "__proto__"라 불리는 property를 더한다. 이것은 constructor 함수의 prototype 객체를 의미한다.
  4. return this를 함수의 끝에 추가한다. 때문에 객체는 함수로부터 return되어 만들어진 것이다. 
student라는 이름의 생성자 함수를 만들었다. 이 함수는 name, age라는 두개의 parameter를 가진다. 이 인자들은 this의 value에 property들을 만든다. 
function Student(name, age) {
  this.name = name;
  this.age = age;
}

이제 new 예악어로 생성자 함수를 호출해보자. 우리는 'John'과 26이라는 두개의 argument들을 넣을 것이다.

var first = new Student('John', 26);

이 코드를 실행한다면 어떤 일이 일어날 것인가?

  1. 새로운 객체를 만들어낸다 ― first 객체
  2. this는 first 객체에 bound된다. 때문에 this에 대한 참조는 first를 향할 것이다. 
  3. __proto__가 추가된다. first.__proto__는 이제 student.prototype을 가리킨다. 
  4. 모든 것이 완료된 후에 새로운 first 객체는 새로운 first 변수에 return된다.

이제 우리는 console.log 선언문을 실행함으로써 이것이 제대로 동작하는지 확인할 것이다. 

console.log(first.name);
// John
console.log(first.age);
// 26

이제 new keyword의 __proto__ 부분에 대해 더 깊이 알아보도록 하자. 

 

 

 

Prototypes

모든 자바스크립트 객체들은 prototype을 가지고 있다. 자바스크립트의 모든 객체들은 자신의 prototype으로 부터 method들과 property들을 상속받는다.

 

이를 확인하기 위해 크롬 개발자를 열고 이 글의 앞에 있는 Student 함수를 type해보자.

function Student(name, age) {
  this.name = name;
  this.age = age;
}

모든 객체들의 prototype을 가지고 있음을 증명하기 위해 이제 아래 코드를 입력해보자.

Student.prototype;
// Object {...}

그러면 이제 객체가 return된다. 이제 새로운 student를 만들어보자.

var second = new Student('Jeff', 50);

우리는 Jeff라는 이름의 두번째 학생을 만들기 위해 Student 생성자 함수를 사용했다. 그리고 new예악어를 사용했기 때문에 __proto__ property는 second 객체에 추가되었다. 이것은 부모 생성자를 가리킨다. 아래 코드를 실행해봄으로써 이것을 확인할 수 있다. 

second.__proto__ === Student.prototype;
// true

 

Student.prototype.constructor은 Student 생성자 함수를 의미한다. 

Student.prototype.constructor;
//  function Student(name, age) {
//    this.name = name;
//    this.age = age;
//  }

 

 

 

 

위 그림에서 보이듯이 Student 생성자 함수는 .prototype이라는 property를 가지고 있다. 이 prototype은 생성자함수를  다시 가리키는 .constructor이라는 객체를 가지고 있다.

이것은 loop이다. 그러므로 우리가 new 예악어를 사용하여 새로운 객체를 생성할 때, 각 객체는 Student.prototype로 되돌아가는 새로운 객체와 연결된 .__proto__ property를 가지고 있다. 

 

상속의 개념을 가지고 있는 이것은 매우 중요하다. prototype 객체는 생성자 함수로 만들어진 모든 객체들 사이에서 사용된다. 이것은 우리가 사용하는 모든 객체들의 prototype에 함수와 property들을 추가할 수 있다는 것을 의미한다. 

 

위 예시들에서 우리는 오직 두개의 Student 객체들을 만들었다. 

 

In our above examples, we only created two Student objects, but what if instead of two students, we have 20,000? All of a sudden, we’re saving a ton of processing power by putting shared functions on the prototype instead of in each of the student objects.

 

좀더 깊이 살펴보기 위해 다른 예제를 살펴보자. 콘솔에 다음 코드를 입력해보자.

Student.prototype.sayInfo = function(){
  console.log(this.name + ' is ' + this.age + ' years old');
}

우리는 다시 한번 Student prototype에 함수를 추가했다. 우리가 새로 추가하거나 이미 추가된 student는 이제 세번째 .sayInfo 함수에 접근이 가능해졌다.  아래 코드를 통해 테스트해보자.

second.sayInfo();
// Jeff is 50 years old

 

새로운 student를 추가하고 한번 더 테스트 해보자. 

var third = new Student('Tracy', 15);
// Now if we log third out, we see the object only has two
// properties, age and name. Yet, we still have access to the 
// sayInfo function:
third;
// Student {name: "Tracy", age: 15}
third.sayInfo();
// Tracy is 15 years old
 
상속이 잘 되었기 때문에 코드는 정상적으로 동작한다. 자바스크립트의 객체에 객체 내부에 우리가 호출하는 property가 있다면 객체는 이 property를 호출한다. 하지만 객체 내부에 호출된 property가 존재하지 않는다면 prototype으로 한단계 올라가서 property를 찾는다. 이런 패턴은 우리가 호출하는 property를 찾거나 전역객체에 이를때가지 반복된다. 
 
상속은 과거에 .toString() 같은 함수를 쓸수 있게된것과 같은 이유이다. 생각해보면 당신은 toString() method를 만들어낸 적이 없었음에도 사용할 수 있었다. 그것은 객체 prototype에 이미 만들어져 있는 JS method들 중 하나이기 때문이다. 우리가 만든 모든 객체들은 궁극적으로 객체 prototype에 상속된다. 그리고 우리는 다음과 같이 이런 method들을 덮어쓸 수 도 있다. 
var name = {
  toString: function(){
    console.log('Not a good idea');
  }
};
name.toString();
// Not a good idea
객체들은 prototype으로 이동하기 전에 method를 가지고 있는지 확인한다. 우리가 method를 가지고 있기 때문에 위 코드는 상속이 없이도 동작하는 것이다. 그러나 이것은 좋은 코딩은 아니다. 전역 method들과 함수 이름은 겹치지 않게 해야한다. 
 
 
 

결론

신입 개발자에게 이것은 이해하기 어려운 개념이지만, 한번 이해하면 좀 더 코드를 명확하고 잘 짤 수 있을 것이다. prototype들로 인해 우리는 특정 코드들을 수백군데에서 사용할 수 있고 수천개의 객체에서도 빠르고 효과적으로 사용할 수 있기 때문이다. 
 

 

 

Comments