this 설명때 있던 new에 관한 글도 마저 번역하며 숙지해보자.
일반 함수 호출
new가 무엇인지 설명하기 위해, new없이 호출되는 일반 함수로부터 시작해보자.
우리는 '사람'객체를 생성하는 함수 하나를 작성할 것이다. 그 함수는 매개변수로 받은것에 기반해 name과 age가 있는 객체를 반환할것이다.
function personFn(name, age) {
var personObj = {};
personObj.name = name;
personObj.age = age;
return personObj;
}
var alex = personFn('Alex', 30); // { name: 'Alex', age: 30 }
아주 간단하다. 객체를 하나 생성하고, 속성들을 넣은 후 리턴한다. 끝이다.
이제 같은 역할을 하는 함수를 하나 만들도록 하자. 하지만 이번엔 new를 사용하여 호출해볼 것이다.
이 함수는 상단에 작성한것과 같은 객체를 만들어낼것이다. 일반적으로 new를 이용해 호출하는 함수를 만들때에는 대문자로 시작하는 함수를 만든다.
이러한 함수를 생성자라고도 한다.
function PersonConstructor(name, age) {
this.name = name;
this.age = age;
}
var alex = new PersonConstructor('Alex', 30); // { name: 'Alex', age: 30 }
personFn으로 호출했을때와 new와 PersonConstructor를 사용해서 호출 했을때 같은 객체가 생성되는것을 볼 수 있다. 왜 일까???????
new키워드는 함수를 특별한 방식으로 호출한다. 우리가 보지 못하는 암시적인 코드를 추가하는 것이다. 위의 함수를 확장하여 어떤 일이 일어나고 있는지 봐보자. 주석으로 표시된 줄은 new를 사용할 때, JS엔진에 의해 암식적으로 추가된 기능을 나타내는 의사코드이다.
function PersonConstructor(name, age) {
// this = {};
// this.__proto__ = PersonConstructor.prototype;
// 다음과 같은 로직이 설정된다.
// 만약 함수 본문에 객체, 배열, 또는 함수를 제외한 모든것을 반환하는 함수를 반환하는 return
// 구문이 있는경우: 해당 return 구문 대신 'this'(새로 생성된 객체)를 반환한다.
this.name = name;
this.age = age;
// return this;
}
이제 new를 해체해보자.
- 새 객체를 만들고 그 객체를 this키워드에 바인딩한다.
- 객체 내부의 [[Prototype]] property와 __proto__를 생성자 함수의 프로토타입이 되도록 설정한다. 이것은 원형적으로 상속된 새 객체의 생성자를 만드는 것이기도 하다.
- 객체, 배열 또는 함수가 아닌 유형의 변수가 함수 본문에 반환되는 경우, 함수에서 this를 반환하는 대신, 새로 생성된 객체를 반환하도록 로직을 설정한다.
- 만약 함수 내부에서 return구문이 없다면 , 함수의 끝에서 this를 return한다.
이제 해체한 부분들이 유효한지 하나씩 살펴보자!
function Demo() {
console.log(this);
this.value = 5;
return 10;
}
/*1*/ var demo = new Demo(); // {}
/*2*/ console.log(demo.__proto__ === Demo.prototype); // true
console.log(demo.constructor === Demo); // true
/*3*/ console.log(demo); // { value: 5 }
function SecondDemo() {
this.val = '2nd demo';
}
/*4*/ console.log(new SecondDemo()); // { val: '2nd demo' }
만일 생성자나 프로토타입에 익숙하지 않더라도, 많이 걱정할 필요는 없다. 자바스크립트를 계속 배우다보면 접하게 될 것이다. 우선 지금은 생성자 함수에 의해 암시적으로 반환된 새 객체가 속성과 메서드를 상속할 수 있다는것을 이해하면 된다.
new로 non-constructor 호출하기
personFn같은 일반함수를 new를 이용해 호출하면 어떤 일이 일어날까?
특별할건 없다. 똑같은 규칙이 적용된다. personFn의 경우, 명시적으로 아무 일도 일어나지 않는 것을 볼 수 있다.
var alex = new personFn('Alex', 30); // { name: 'Alex', age: 30 }
왜일까? personFn에 암시적 코드를 추가해보자.
function personFn(name, age) {
// this = {};
// this.constructor = PersonConstructor;
// this.__proto__ = PersonConstructor.prototype;
// 다음과 같은 로직이 설정된다.
// 만약 함수 본문에 객체, 배열, 또는 함수를 제외한 모든것을 반환하는 함수를 반환하는 return
// 구문이 있는경우: 해당 return 구문 대신 'this'(새로 생성된 객체)를 반환한다.
var personObj = {};
personObj.name = name;
personObj.age = age;
return personObj;
// return this;
}
암시적인 코드는 똑같이 추가되었다.
- 새로운 객체에 this를 바인딩하고, 그것을 생성자와 프로토타입에 설정한다.
- 객체가 아닌것대신 this를 return 하는 구문이 추가되었다.
- 마지막에 암시적인 return this 구문이 추가되었다.
우리는 this키워드를 코드에서 사용하지 않았기 때문에 우리의 코드에 영항을 주지 않았다. 또한 우리는 명시적인 객체인 personObj를 return해주고 있기 때문에 반환하는 로직과 return this 구문은 쓸모가 없다. 효과적으로, new를 사용해 함수를 호출하는것은 결과물에 아무런 영향이 없다. 만약 우리가 this나 객체를 return하지 않았다면 함수는 new를 사용할때와 사용하지 않을때 다른 결과물을 나타낼것이다.
출처 : https://codeburst.io/javascripts-new-keyword-explained-as-simply-as-possible-fec0d87b2741
'Frontend > Javascript' 카테고리의 다른 글
[javascript] 웹 페이지에서 javascript가 하는 일 (0) | 2021.09.12 |
---|---|
[javascript] 동기 / 비동기 (1) | 2021.08.30 |
Javascript this (4) | 2021.08.13 |