This in JS

October 14, 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 메서드

            • 객체(레퍼런스 타입)의 실제 값을 얻기 위해 사용되는 GetValue 메소드가 존재하며, 이 메서드는 프로토타입 체인을 통해, 상속된 속성까지 모두 분석 후, 객체 속성(propertyName)의 실제 값을 반환해준다.

              
              // 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 메서드

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

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

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

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

      
      // 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 속성 값으로 초기화된다.

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

        • 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())

            • 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.

              
                // global execution context
              
                function A() {
              
                  // function Execution Context
              
                  function B() {
                    console.log(this); // this === null => global object
                  }
              
                  B(); // AO.B() == null.B()
                }
              
                A();
          • ECStack 내부

              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 값은 생성된 객체초기화 된다.

            
              // global Execution Context
            
              function A(){
            
                // function Execution Context
            
                this.id = 'mohwa';
                
                // new 연산자 + 생성자 함수를 통해 생성된 객체로 초기화된다.
                console.dir(this); // A object
              }
              
              // 객체를 생성한다.
              new A;

          • new 연산자 매커니즘 Pseudo-Code

            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;
            }

        • 함수 호출 시 this 값을 초기화 하는 방법

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

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

            
            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 값을 초기화한다.

            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


Profile picture

Written by mohwa