파트 1 - 3) 객체: 기본 - 5) new 연산자와 생성자 함수

Lee·2021년 10월 21일
0


new 연산자와 생성자 함수 파트 링크 : https://ko.javascript.info/constructor-new

생성자 함수

'new' 연산자와 생성자 함수를 사용하면 유사한 객체 여러 개를 쉽게 만들 수 있다.

생성자 함수와 일반 함수는 기술적인 부분에서 차이가 없지만 규칙이 다르다.
생성자 함수는 첫글자를 대문자로 쓰고, 반드시 앞에 new 연산자를 붙여 실행한다.

new 생성자를 쓰게 되면
1. 빈 객체를 만들어 this에 할당
2. 함수 본문을 실행하여 this에 새로운 프로퍼티를 추가해 this를 수정
3. this를 암시적으로 반환
이 세 과정으로 실행하게 된다.

<script>
  function User(name) {
    this.name = name;
    this.isAdmin = false;
  }

  let user = new User("보라");

  alert(user.name); // 보라
  alert(user.isAdmin); // false
  
  //------------동작과정↓----------------
  
  function User(name) {
  
  // 1.this = {};  (this가 new 생성자를 통해 새로 만들어진 빈 객체를 가리킴)

  // 2. 함수 본문이 실행되어 새로운 프로퍼티를 빈 객체가 할당된 this에 추가함
  this.name = name;
  this.isAdmin = false;

  //3. return this;  (생성자 함수는 이 this를 반환한다.=> 중요!)
}
</script>

주의!
모든 함수는 new가 붙어 생성자 함수가 될 수 있다!
그리고 이름의 첫 글자가 대문자인 함수는 new를 붙여 실행하는 것이 약속이다!

  • 매개변수가 없는 생성자는 괄호를 생략하여 let user = new User; 이런식으로도 호출할 수 있지만 좋은 스타일은 아니다.

재사용할 필요가 없는 복잡한 객체 생성

익명 생성자 함수로 감싸주는 방식을 사용할 수 있다!

<script>
  let user = new function() {
    this.name = "John";
    this.isAdmin = false;

    // 사용자 객체를 만들기 위한 여러 코드.
    // 지역 변수, 복잡한 로직, 구문 등의
    // 다양한 코드...
  };
</script>

위처럼 생성자 함수를 익명 함수로 정의하면 익명 함수이기 때문에 어디에도 저장되지 않는다.
저장되지 않으므로 재사용이 불가능하다.
이렇게 익명 함수로 생성자 함수를 정의하면 재사용은 막으면서 코드를 캡슐화 할 수 있다.

  • 캡슐화 : 객체 지향 프로그래밍의 측면에서 볼 수 있는 특징으로
  1. 객체의 속성(data fields)과 행위(메서드, methods)를 하나로 묶고,
    => 서로 관련이 있는 속성과 메서드들을 하나의 틀에 담는 것. (ex. 자바의 클래스)

  2. 실제 구현 내용 일부를 외부에 감추어 은닉한다.
    => ex) 외부에서 직접 접근이 불가능하고 getter, setter 메서드를 사용하여 접근 가능하도록 제한을 두는 것.
    (참고: https://alcohol-dev.tistory.com/1)


new.target과 생성자 함수 (심화 학습)

이 문법은 자주 쓰이는 문법은 아니다.

new.target 프로퍼티를 사용하면 함수가 new와 함께 호출되었는지 아닌지를 알 수 있다.

일반적인 방법으로 함수를 호출했다면 new.target은 undefined를 반환한다.
함수를 new와 함께 호출한 경우엔 new.target은 함수 자체를 반환해줍니다.

<script>
  function User() {
    alert(new.target);
  }

  // 'new' 없이 호출
  User(); // undefined

  // 'new'를 붙여 호출
  new User(); // function User { ... }
</script>

함수 본문에서 new.target을 사용하면 해당 함수가 new와 함께 호출되었는지(in constructor mode) 아닌지(in regular mode)를 확인할 수 있다.

이를 이용하여 new를 이용하지 않고 호출한 함수를 new를 붙여 호출한 함수처럼 바꿔줄 수 있다.

<script>
  function User(name) {
    if (!new.target) { // new 없이 호출하면
      return new User(name); // new를 붙인 함수를 반환
    }

    this.name = name;
  }

  let bora = User("보라"); // 'new User'를 쓴 것처럼 호출된 함수로 새 값이 저장된 this가 bora에 할당된다.
  alert(bora.name); // 보라
</script>

하지만 아시다시피... new 생성자를 굳이 안 붙이고 위와 같이 작성할 일은 정말정말 거의 없다.


생성자와 return문

생성자 함수에서는 반환해야 할 것들이 모두 this에 저장되고, this가 자동으로 반환되기 때문에 반환문을 명시적으로 써 줄 필요가 없다.

그럼에도 생성자 함수에 return 문을 쓴다면?

  1. 객체를 return 하면 this 대신 해당 객체가 반환된다.
  2. 원시형을 return 하면 return문이 무시된다.
<script>
  function BigUser() {

    this.name = "원숭이";

    return { name: "고릴라" };  // <-- this가 아닌 새로운 객체를 반환함
  }

  alert( new BigUser().name );  // 고릴라
</script>

하지만 역시나 return 문이 있는 생성자 함수는 거의 쓰이지 않는다.


생성자 내 메서드

객체의 프로퍼티에 함수(메서드)를 할당할 수 있는 것처럼 생성자 함수를 통해 만들어진 this에도 메서드를 할당할 수 있다.

<script>
  function User(name) {
    this.name = name;

    this.sayHi = function() {
      alert( "제 이름은 " + this.name + "입니다." );
    };
  }

  let bora = new User("이보라");

  bora.sayHi(); // 내 이름은 이보라입니다.

  /*
  bora 에는 {
     name: "이보라",
     sayHi: function() { ... }
  } 객체가 할당 되어있다.
  */
</script>

class 문법 또한 생성자 함수와 같이 복잡한 객체를 만들 수 있는데 이는 추후에 학습한다고 한다.

profile
하고 싶은 게 너무 많습니다.

0개의 댓글

관련 채용 정보