This in JS

14 Oct 2015

  • this 값은 Execution Context 의 속성 중 하나이다.

      var ECStack = [
        globalExecutionContext: {
          VO: {
          },
          this: global object
        }
      ];
    

  • this 값은 해당 Execution Context **진입 시 초기화**된 후, 그 이 변하지 않는다.

        
      // global Execution Context
        
      // 실행 코드 처리 시 새로운 값을 할당할 수 없다.
      this.window = null;
    
      // 실행 코드 처리 후 값이 변하지 않는다.
      console.log(this.window); // global object
        
    
  • 레퍼런스 타입(Reference Type)

    • 레퍼런스 타입은 base 와 propertyName 속성을 가진 객체로 표현할 수 있으며, 설명을 목적으로 “ECMA 스펙” 에서 정의하고 있는 개념이다.

      
          // 아래는 레퍼런스 타입을 나타내는 pseudo-code 이다.
          var valueOfReferenceType = {
            base: <base object>,
            propertyName: <property name>
          };
      
      • 레퍼런스 타입은 오직 두 가지 경우에만 있을 수 있다.

        • 식별자(identifier)

          • 식별자는 변수 이름, 함수 이름, 함수 Argument 이름으로 나뉜다.

          • 변수 이름

            
            // global Execution Context
            
            // A 변수 선언
            var A = 1;
            
            console.log(A); // 1
            
          • 레퍼런스 타입 내부

            var AReference = {
              base: global object,
              propertyName: 'A'
            };
            
          • 함수 이름

              // global Execution Context
                            
              // A 함수 선언
              function A(){
                    
              };
                            
              console.log(A); // A function object
                                                
            
          • 레퍼런스 타입 내부

            ```javascript
            var AReference = {
              base: global object,
              propertyName: 'A'
            };
            ```
            
          • GetValue 메서드

            - <u><strong>객체</strong>(레퍼런스 타입)의 실제 값을 얻기 위해 사용되는 <span style="color:#6298c1">GetValue</span> 메소드가 존재하며</u>, 이 메서드는 <strong>프로토타입 체인</strong>을 통해, 상속된 <strong>속성</strong>까지 모두 분석 후, <strong>객체 속성</strong>(propertyName)의 실제 값을 <strong>반환</strong>해준다.
            
                ```javascript
                              
                // GetValue 메서드를 나타내는 pseudo-code 이다.
                function GetValue(value) {
                                
                  if (Type(value) != Reference) {
                    // 레퍼런스 타입이 아니면 값을 그대로 돌려준다.
                    return value;
                  }
                                
                  // base 속성 값을 가져온다.
                  var base = GetBase(value);
                                
                  // base 속성 값이 null 인 경우
                  if (base === null) {
                    throw new ReferenceError;
                  }
                                
                  // propertyName 속성 값을 가져온다.
                  var propertyName = GetPropertyName(value);
                                
                  // [[Get]] 메서드는 프로토타입 체인으로부터, 상속된 속성까지 모두 분석 후 속성의 실제 값을 돌려준다.
                  return base.[[Get]](propertyName);
                                
                }
                              
                GetValue(ReferenceType);
                              
                ```			
            
        • 프로퍼티 접근자(property accessor)

          • obj 객체의 A 메서드

            ```javascript
            // global Execution Context
                  
            var obj = {
              A: function(){
                return this;
              }
            };
                  
            console.log(obj.A()); // obj Object
            console.log(obj['A']()); // obj Object
            ```
            
          • 레퍼런스 타입 내부

            ```javascript
            var objAReference = {
              base: obj Object,
              propertyName: 'A'
            };
            ```
            
          • GetValue 메서드를 통해 해당 속성(propertyName) 값을 반환한다.

            ```javascript
            GetValue(objAReference); // A function object
            ```
            
  • 전역 코드 안의 this

    • 전역 코드안의 this전역 객체 자신이된다.

      ```javascript
          
      // global code in global Execution Context
            
      console.log(this); // global object
        
      console.log(this.window); // global object
        
      console.log(this === this.window); // true
      ```
      
  • 함수 코드 안의 this

    • 함수 코드의 경우 this가리키는 **대상**이 매번 달라질 수 있다.

      • Function Execution Context 진입 시 this 가 가지는 초기화 값은 **호출 표현식 형태**에 의해 달라진다.

      • 함수 코드 안의 this 값이 초기화되는 과정

        • 만약 ()(함수 호출 괄호) 왼편의 (식별자 또는 프로퍼티 접근자)가 레퍼런스 타입일경우, 함수 코드 안의 this 값은 해당 **레퍼런스 타입**의 **base** 속성 값으로 **초기화**된다.<p>

        • 그러나 레퍼런스 타입이 아닌 경우, this 값은 자동으로 null 을 갖게되며, nullthis 값으로 **평가**될 수 없기때문에, **암묵적**으로 **전역 객체**로 **변환**된다.<p>

        • A 함수

            // global Execution Context
          
            function A(){
          
              // function Execution Context
              // this 값은 해당 레퍼런스 타입의 base 속성 값으로 초기화된다.
              console.log(this); // global object
            };
          
            // [호출자].[propertyName](호출괄호)
            this.A(); // this.A();
          
        • 레퍼런스 타입 체크

          
            // reference Type
            var AReference = {
              base: global object,
              propertyName: 'A'
            };
          
            // referenceType 값을 반환한다.
            GetValue(AReference); // A function object
          
          
        • obj 객체의 X 메서드

          
            // global Execution Context
          
            var obj = {
              X: function(){
                return this;
              }
            };
          
            console.log(obj.X()); // obj Object
            console.log(obj['X']()); // obj Object
          
        • 레퍼런스 타입 체크

          
            // reference Type
            var objXReference = {
              base: obj Object,
              propertyName: 'X'
            };
          
            // referenceType 값을 반환한다.
            GetValue(objXReference); // X function object
          
        • obj 객체의 A 메서드를 x 변수에 할당한다.

          
            // global Execution Context
          
            var obj = {
              A: function(){
                return this;
              }
            };
          
            // x 변수 선언
            var x = obj.A;
          
            console.log(x()); // global object
          
        • 레퍼런스 타입 체크

          
            // reference Type
            var objAReference = {
              base: obj Object,
              propertyName: 'A'
            };
          
            // reference Type
            var xReference = {
              base: global object,
              propertyName: 'x'
            };
          
            // referenceType 값을 반환한다.
            GetValue(xReference); // A function object
          
        • 레퍼런스 타입이 아닌 함수 표현식(즉시 실행 함수)

            // global Execution Context
          
            // 식별자 또는 프로퍼티 접근자가 아닌 함수 표현식
            (function () {
              // 이 경우 레퍼런스 타입이 존재하지 않으므로, 결국 null 을 반환 후 자동으로 전역 객체로 변환된다.
              console.log(this); // null => global object
            })();
          
        • 레퍼런스 타입 체크

          
            // 식별자 또는 프로퍼티 접근자가 아닌 함수 표현식(즉시 실행 함수)은 reference Type 값이 존재하지 않는다.
          
        • 함수 내부에 선언된 함수

          • A 함수 내부에 선언된 B 함수는 AO(VO) 가 갖는 속성 중 하나이다. 또한 AO(VO) 는 항상 this 값을 null 로 반환하기 때문에, 결국 B 함수 내부 this 는 global object 를 갖게된다.(AO.B() === null.B())<p>

            • The activation object always returns as this value — null (i.e. pseudo-code AO.bar() is equivalent to null.bar()). Here again we come back to the described above case, and again, this value is set to global object.

              ```javascript
              

              // global execution context

              function A() {

              // function Execution Context
                    
              function B() {
                console.log(this); // this === null => global object
              }
                    
              B(); // AO.B() == null.B()   }
              

              A(); ```

          • ECStack 내부

            ```javascript
              var ECStack = [
                <B> activeFunctionExecutionContext: {
                  AO(VO): {
                    arguments: {
                    }
                  },
                  this: null ==> global Object                          
                },                      
                <A> functionExecutionContext: {
                  AO(VO): {
                    arguments: {
                    }
                    B: < reference to function >
                  },
                  this: global Object                          
                },
                globalExecutionContext: {
                  VO: {
                    A: < reference to function >
                  },
                  this: global object                        
                }
              ];
            ```
            
          • 레퍼런스 타입 체크

            
                // reference Type
                var BReference = {
                  base: null,
                  propertyName: 'B'
                };
            
                // referenceType 값을 반환한다.
                GetValue(BReference); // B function object
            
        • 생성자 함수 호출

          • new 연산자의 객체 매커니즘에 따라 this 값은 생성된 객체초기화 된다.

             ```javascript
                    
               // global Execution Context
                    
               function A(){
                    
                 // function Execution Context
                    
                 this.id = 'mohwa';
                                
                 // new 연산자 + 생성자 함수를 통해 생성된 객체로 초기화된다.
                 console.dir(this); // A object
               }
                              
               // 객체를 생성한다.
               new A;
             ```
             ![](https://www.dropbox.com/s/4mkmvx22cmlo7ow/92.jpg?dl=1)
            
          • new 연산자 매커니즘 Pseudo-Code

             ```javascript
             function A(){
                    
               this.id = 'mohwa';
                    
               console.dir(this); // A instance
             }
                    
             var o = New(A);
                    
             console.dir(o); // A instance
                    
             // new 연산자 구현
             function New(constructor) {
                    
               constructor = constructor || function F(){};
                    
               var o = {};
                    
               // 전달받은 생성자 함수 객체의 원형을 o 객체의 원형으로 위임한다.
               o.__proto__ = constructor.prototype;
                    
               // 생성자 함수 객체의 this 값을 o 객체로 초기화한다.
               constructor.call(o);
                    
               return o;
             }
             ```	
             ![](https://www.dropbox.com/s/j4xkyq7ixpdvcbf/93.jpg?dl=1)
            
        • 함수 호출 시 this 값을 초기화 하는 방법

          • Function.prototype 객체 메서드인 callapply 메서드를 통해, 함수 호출 시 this 값을 초기화할 수 있다.<p>

          • call 메서드를 통해 전달된 객체this 값을 초기화한다.

             ```javascript
                            
             function A(x, y){
            
               // function execution context
            
               console.dir(this); // obj Object
            
               console.log(x); // 1
               console.log(y); // 2
            
             }
            
             var obj = {
               id: 'mohwa'
             };
            
             // A 함수 객체의 this 값을 obj 객체로 초기화 한다.
             A.call(obj, 1, 2);
             ```
            
          • apply 메서드를 통해 전달된 객체this 값을 초기화한다.

             ```javascript
             function A(x, y){
            
               console.dir(this); // obj Object
            
               console.log(x); // 1
               console.log(y); // 2
             }
            
             var obj = {
               id: 'mohwa'
             };
            
             // A 함수 객체의 this 값을 obj 객체로 초기화 한다.
             A.apply(obj, [1, 2]);
             ```
            

참고 URL

comments powered by Disqus