[Java Script] 함수와 프로토타입 체이닝 3

2021. 8. 5. 15:30CSE/Java Script

<호출 패턴과 this 바인딩>

- arugments 객체 뿐만 아니라 this 인자가 함수 내부로 암묵적으로 전달됨

- 함수가 호출되는 방식인 호출 패턴에 따라 this가 다른 객체를 참조한다 (this 바인딩)

 

1. 객체의 메서드 호출할 때, this 바인딩

- 메서드 : 객체의 프로퍼티가 함수인 경우

- 메서드를 호출할 때, 해당 메서드 내부의 this는 메서드를 호출한 객체가 된다.

var myObject= {
    name : 'foo',
    sayName:function(){
        console.log(this.name);
    }
};

var otherObject = {
    name : 'bar'
};

otherObject.sayName = myObject.sayName;

myObject.sayName(); //foo
otherObject.sayName(); //bar

 

2. 함수를 호출할 때 this 바인딩

- 함수 내부 코드에서 사용된 this는 전역 객체에 바인딩이 된다.

=> 브라우저의 경우 window 객체가 되고, Node.js에서는 global 객체가 된다.

 

- 모든 전역 변수는 전역 객체의 프로퍼티이다.

 

 

 

 

 

 

 

 

 

- 함수 호출에서 this 바인딩 특성은 내부 함수를 호출했을 경우에도 적용되므로, 내부 함수에서 this를 이용할 때는 주의해야 한다.

- 객체의 프로퍼티인 func1의 this는 해당 객체인 myObject에 바인딩이 되지만, 내부 함수인 func2, func3는 전역 객체에 바인딩이 된다.

=> 이를 극복하는 방법은 부모 함수의 this를 내부함수가 접근 가능한 다른 변수에 저장하는 것이다. 주로 that이라는 변수에 저장한다.

- 자바스크립트에서는 this 바인딩의 한계를 극복하려고, this 바인딩을 명시적으로 할 수 있도록 call과 apply 메서드를 제공한다.

 

3. 생성자 함수를 호출할 때 this 바인딩

- 자바 스크립트의 생성자 함수는 객체를 생성하는 역할을 한다

=> 기존 함수에 new 연산자를 붙여서 호출하면 해당 함수는 생성자 함수로 동작한다.

//생성자 함수
var Person = function (name){
    this.name = name;
}

//생성자 함수를 통해 객체 생성
var foo = new Person('Ella');
console.log(foo.name); //Ella

** 생성자 함수가 동작하는 방식**

  1. 생성자 함수 코드가 실행 되기 전, 빈 객체가 생성되고, 생성자 함수 내부의 this는 해당 빈 객체를 가리킨다.
  2. 생성자 함수 내부에서 this를 사용해서 생성된 빈 객체에 동적 프로퍼티나 메서드를 추가할 수 있다.
  3. 생성자 함수에서 리턴문이 없으면 해당 객체인 this를 return한다.

** 객체 리터럴 방식 vs 생성자 함수 방식 **

- 객체 리터럴 방식 : 같은 형태의 객체를 재생성할 수 없다

- 생성자 함수 방식 : 같은 형태의 서로 다른 객체를 재생성할 수 있다.

- 객체 리터럴 방식과 생성자 함수 방식의 차이가 프로토타입 객체에 있음을 알 수 있다.

=> 왜 프로토타입 객체에 차이가 발생할까? : 자바 스크립트 객체 생성 규칙 때문

=> 자바스크립트 객체는 자신을 생성한 생성자 함수의 prototype 프로퍼티가 가리키는 객체를 자신의 프로토타입 객체로 설정한다

 

** 생성자 함수를 new를 붙이지 않고 호출할 경우 **

- 생성자 함수를 new 없이 호출하거나 일반 함수를 new를 붙여서 호출할 경우 오류가 발생한다.

=> 일반 함수 호출과 생성자 함수를 호출할 때 this 바인딩 방식이 다르기 때문

- 일반 함수 : this가 window 전역 객체에 바인딩

- 생성자 함수 : this 새로 생성되는 빈 객체에 바인딩

- 따라서 생성자 함수를 new 없이 호출하게 되면, this가 바인딩된 window에 동적으로 name과 gender 프로퍼티를 생성하게 되는 것이다.

=> 따라서 생성자 함수로 사용할 함수는 첫 글자를 대문자로 표기하는 네이밍 규칙을 권장한다.

 

+ 객체를 생성하는 별도의 코드 패턴

function A(arg){
    if (!(this instanceof A))
        return new A(arg);
    
    this.value = arg ? arg : 0 ;
}

- this가 해당 함수의 인스턴스인지 확인하고 아니라면 new를 붙여서 실행한 생성자 함수 결과를 리턴하도록 한다.

 

4. call과 apply 메서드를 이용한 명시적인 this 바인딩

- apply()와 call() 메서드는 Function.prototype 객체의 메서드이므로 모든 함수들이 호출할 수 있다.

함수.apply(this를 바인딩할 객체, 함수에 넘겨줄 인자 배열);
함수.call(this를 바인딩할 객체, 함수에 넘겨줄 인자1, 인자2 ...);

-  이런 메서드를 호출하는 주체가 함수이기 때문에 본질적인 기능은 함수 호출이다.

=> 즉 함수.apply()의 기본적인 기능은 Person() 함수를 호출하는 것

=> Person('foo', 30) 함수를 호출하면서 this를 foo 객체에 명시적으로 바인딩하는 것을 의미한다

 

- 대표적인 용도 : 유사 배열 객체에서 배열 메서드 사용하는 경우

=> Array.prototype.slice() 메서드를 호출하는데, 이 때 this는 arugments 객체로 바인딩해라

=> arguments 객체가 Array.prototype.slic() 메서드를 마치 자신의 것 처럼 사용하게 된다.

 

5. 함수 리턴

- 자바 스크립트 함수는 리턴문을 사용하지 않았더라도 다음의 규칙으로 항상 리턴값을 전달한다.

  • 일반 함수나 메서드는 리턴값을 지정하지 않을 경우, undefined 값이 리턴됨
  • 생성자 함수에서 리턴값을 지정하지 않을 경우 생성된 객체가 리턴된다.
  • 생성자 함수에서 리턴값을 지정하였더라도, 객체가 아니라면 해당 리턴값은 무시하고 this로 바인딩된 객체가 리턴된다.