• JavaScript 

    이 글에서는, 생성된 객체GC 에 의해, 소멸되는 시점에 대해 테스트해볼 것이다.

    • Global Execution Context 내부

      • 테스트 1

                
           // global execution context
           function A(){}
                
           // A 생성자 함수 객체를 통해 새로운 객체를 생성한다.
           var obj = new A();
                
           console.log(obj) // object Object
        
      • HEAP MEMORY CHECK

        • 해당 객체Heap Memory 영역에 존재하는것을 볼 수 있다.

          ![](/blog/assets/images/posts/20151030/variable_2.png)
          
      • 테스트 2

           // global execution context
           function A(){}
                
           // A 생성자 함수 객체를 통해 새로운 객체를 생성한다.
           var obj = new A();
                 
           // obj 변수에 null 값을 할당하여, 생성된 객체를 GC 대상으로 만든다.
           obj = null;
                
           console.log(obj) // null
        
      • HEAP MEMORY CHECK

        • obj = null 코드를 통해, 해당 객체GC 대상으로 만들었다.

        • 해당 객체Heap Memory 영역에서 소멸된 것을 볼 수 있다.

          ![](/blog/assets/images/posts/20151030/variable_3.png)
          
      • 테스트 3

           // global execution context
           function A(){}
                
           // A 생성자 함수 객체를 통해 새로운 객체를 생성한다.
           var obj = new A();
                
           // x 변수에 obj 값(객체 참조 포인터)을 할당한다.
           var x = obj;
                
           // obj 변수에 null 값을 할당하여, 생성된 객체를 GC 대상으로 만든다.
           obj = null;
                
           // 해당 객체(new A())를 참조하는 대상(x 변수)이 아직 남아있기때문에, GC 에 의해 Heap Memory 영역에서 소멸되지않는다.
           console.log(x) // obj Object
        
      • HEAP MEMORY CHECK

        • 해당 객체를 참조하는 대상이 아직 남아있기때문에, GC 에 의해 Heap Memory 영역에서 소멸되지않는다.

          ![](/blog/assets/images/posts/20151030/variable_4.png)
          
      • 테스트 4

           // global execution context
           function A(){}
                
           // A 생성자 함수 객체를 통해 새로운 객체를 생성한다.
           var obj = new A();
                
           // x 변수에 obj 값(객체 참조 포인터)을 할당한다.
           var x = obj;
                
           // obj 변수에 null 값을 할당하여, 생성된 객체를 GC 대상으로 만든다.
           obj = null;
                
           // x 변수에 null 값을 할당하여, 생성된 객체를 GC 대상으로 만든다.
           x = null;
                
           // x 변수에 새롭게 할당된 null 값이 반환된다.
           console.log(x) // null
        
      • HEAP MEMORY CHECK

        • 해당 객체를 참조하는 대상이 모두 사라졌기때문에, 객체Heap Memory 영역에서 소멸된 것을 볼 수 있다.

          ![](/blog/assets/images/posts/20151030/variable_5.png)
          
      • 반드시 null 값만 할당해야 하는가?

        ```javascript
        // global execution context
        function A(){}
            
        // A 생성자 함수 객체를 통해 새로운 객체를 생성한다.
        var obj = new A();
            
        // obj 변수에 다른 값을 할당하여, 생성된 객체를 GC 대상으로 만든다.
        obj = 1;
            
        console.log(obj) // 1
        ```
        
        • HEAP MEMORY CHECK

          • null 값이 아닌, 다른 값을 할당해도, 객체Heap Memory 영역에서 소멸된다.

            ![](/blog/assets/images/posts/20151030/variable_5.png)                        
            
    • Function Execution Context 내부

      • x 변수에는 obj 변수에 할당된 객체 참조 포인터(값)가 할당된다.

        ```javascript
        // global execution context
            
        // obj 변수에 객체를 할당한다.
        var obj = {x: 1};
            
        function B(){
            
            // function execution context
                
            // x 변수를 obj 변수 값으로 초기화한다.
            // obj 변수 값: 객체 참조 포인터
            var x = obj;
            
            // x 변수를 통해, 객체를 확장한다.
            x.y = 2;
            
            console.log(obj); // {x: 1, y: 2}
        }
            
        B();
        ```
        
      • 테스트 1

        ```javascript
        // global execution context
        function A(){};
            
        // A 생성자 함수 객체를 통해 새로운 객체를 생성한다.
        var obj = new A();
            
        function B(){
            
            // function execution context
                
            // obj 변수에 null 값을 할당하여, 생성된 객체를 GC 대상으로 만든다.
            obj = null;
            
            console.log(obj);
        }
            
        B();
        ```
        
        • HEAP MEMORY CHECK

          • 예상했던대로, 객체Heap Memory 영역에서 소멸된다.

            ![](/blog/assets/images/posts/20151030/variable_7.png)
            
      • 테스트 2

        ```javascript
        // global execution context
            
        function A(){};
            
        // A 생성자 함수 객체를 통해 새로운 객체를 생성한다.
        var obj = new A();
            
        function B(){
            
            // function execution context
            
            var x = obj;
            // obj 변수에 null 값을 할당하여, 생성된 객체를 GC 대상으로 만든다.
            obj = null;
            
            console.log(obj); // null
            
            // 해당 객체(new A())를 참조하는 대상(x 변수)이 아직 남아있기때문에, GC 에 의해 Heap Memory 영역에서 소멸되지않았다.
            console.log(x); // object Object
        }
            
        B();
        ```
        
        • HEAP MEMORY CHECK

          • 함수 종료 후(== AO 가 소멸되는 시점)에는 해당 객체를 참조하는 대상이 모두 사라졌기때문에, 객체Heap Memory 영역에서 소멸된 것을 볼 수 있다.

            ![](/blog/assets/images/posts/20151030/variable_8.png)
            
      • 테스트 3

        ```javascript
        // global execution context
            
        function A(){};
            
        // A 생성자 함수 객체를 통해 새로운 객체를 생성한다.
        var obj = new A();
            
        function B(){
            
            // function execution context
            
            // x 는 globalExecutionContext 내부 VO 의 새로운 속성으로 추가된다.
            x = obj; // === this.x = obj;
            // obj 변수에 null 값을 할당하여, 생성된 객체를 GC 대상으로 만든다.
            obj = null;
            
            console.log(obj); // null
            
            // 해당 객체(new A())를 참조하는 대상(x 변수)이 아직 남아있기때문에, GC 에 의해 Heap Memory 영역에서 소멸되지않았다.
            console.log(x); // object Object
        }
            
        B();
        ```
        
        • HEAP MEMORY CHECK

          • 이 같은 경우, 함수 종료 후(== AO 가 소멸되는 시점)에도 해당 객체를 참조하는 대상(globalExecutionContext.VO.x)이 아직 남아있기때문에, 객체Heap Memory 영역에서 소멸되지 않는다.

            ![](/blog/assets/images/posts/20151030/variable_9.png)            
            

    테스트 결과

    • var x = obj 코드를 통해, x 변수에는 obj 변수에 할당된 객체 포인터(값)가 할당된다.<p>

    • 생성된 객체는 그 객체를 참조하는 대상이 없을경우에만 GC 에 의해, Heap Memory 영역에서 소멸된다.<p>

      • null(or 다른 값) 값만 할당한다고 무조건 소멸되는 것은 아니다.
    • null 값이 아닌, 다른 값을 할당해도, 객체Heap Memory 영역에서 소멸된다.

    • JS 는 개발자가 직접 Heap Memory 영역에 할당된 객체소멸시킬 수 있는 방법을 제공하지 않는다.

      • null 값을 할당하거나, delete 연산자를 통해 VO 의 속성을 삭제하는것은, 모두 간접적으로 GC를 통해, 객체소멸시키는 방법들이다.<p>
    • AO 의 속성으로 할당된 객체 참조함수 종료 시 모두 GC 에 의해 소멸된다.<p>

    참조 URL

    Read more


  • javascript 

    1. 정의

    • 객체 지향 언어는 크게 두 가지 줄기로 나눌수 있다.

    • 클래스 기반 언어프로토타입 기반언어의 차이

      • 클래스 기반 언어

        • 클래스 기반 언어에서는, 객체의 형식이 정의된 클래스라는 개념을 가진다.

          ```javascript
              
          // 클래스를 선언한다.
          public class Person
          {
            // Field
            public string name;
              
            // Constructor that takes no arguments.
            public Person()
            {
              name = "unknown";
            }
              
            // Constructor that takes one argument.
            public Person(string nm)
            {
              name = nm;
            }
              
            // Method
            public void SetName(string newName)
            {
              name = newName;
            }
          }
                  
          // person1 변수는 Person 클래스를 통해 생성된 객체를 참조하게된다.
          Person person1 = new Person();
          ```
          
        • 클래스 기반 언어만의 상속 개념을 가진다.

          ```javascript
          // Employee: 상속 클래스
          // Manager: 파생 클래스
          public class Manager : Employee
          {
            // Employee fields, properties, methods and events are inherited
            // New Manager fields, properties, methods and events go here...
          }		
          ```
          
        • [번외] 그럼 클래스 기반 언어클래스는 어떻게 생성되었을까?

          • 아래 글은 “skyul” 님의 글을 발췌한 내용입니다

            ```javascript
                    
            프로토타입 기반 OO는 객체를 직접 이용하는데 비해, 클래스 기반의 OO는 클래스라는 틀을 이용해서 객체를 생성하죠.
                    
            자연스럽게 나오는 질문은 "그럼 클래스는 대체 어디서 나온 것인가?"라는 거죠.
                    
            대표적 클래스 기반 OO인 Java는 클래스도 객체로 봅니다. 그런데 클래스가 객체면 클래스를 찍어낸 클래스가 있어야 합니다. 클래스를 찍어낸 클래스도 객체이므로, 클래스를 찍어낸 클래스를 만드는 클래스도 있어야 합니다. 
                        
            이렇게 무한히 반복 되기 때문에 "inifnite regress problem of classes"라고 불리는 것이죠.
                    
            Java는 이 문제를 java.lang.Class가 모든 클래스의 틀이라고 이야기하면서, 은근 슬쩍 넘어갔지만 여기에 숨은 논리적인 문제를 확실히 못풀고 "태초에 Class가 있었다"라는 해법이 나와버리는거죠.
                    
            다른 접근 방법을 취한 언어가 있는지 모르겠지만, 대부분의 클래스 기반 언어는 클래스는 second-order citizen으로 특별히 취급해서 찍어낼 수 있는 틀은 원래 있었다라고 얘기하게 되는거죠.
                        
            그 대상이 클래스라는 거만 제외하면 접근 방법은 프로토타입 방식과 크게 다르지 않은 거고요.
            ```
            
      • 프로토타입 기반 언어

        • 프로토타입 기반 언어에서는 클래스라는 개념이 존재하지 않으며, 여러 종류의 Built-in 객체들이 시스템상에 존재하게된다. 또한 클래스 기반언어상속 개념과 달리, 객체 원형위임 과정을 통해 상속 과정이 구현된다.

          • 프로토타입 기반 언어클래스가 존재하지 않는다.

            - 함수 객체는 클래스가 아닌 <strong>First-Class Objects</strong>이다.<p>
                  
            - 선언된 함수 객체는, **프로토타입 기반 언어**의 특징인, **위임** 과정을 통해 만들어진 객체의 <span style="color:#c11f1f">원형</span>을 참조하고있다.
                  
            - 즉, JS <strong>함수</strong>는 [Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions) 생성자 함수 객체의 <span style="color:#c11f1f">원형</span>(Function.prototype)을 <strong>참조</strong>하는 또 다른 <strong>함수 객체</strong>일뿐이다.
              
                ``` javascript
                      
                // A 함수 객체를 선언한다.
                function A(){
                }
                      
                // 선언된 A 함수 객체의 데이터 타입은 function 타입을 반환한다.
                console.log(typeof A); // function
                      
                // 선언된 A 함수 객체의 생성자 함수는 Function 생성자 함수 객체를 가리키고있다.
                console.dir(A.constructor); // Function
                      
                // 선언된 A 함수 객체의 생성자 함수 객체
                console.dir(Function); // Function
                      
                // 선언된 A 함수 객체는 위임 과정을 통해, 자신을 만든 생성자 함수(Function) 객체의 원형(Function.prototype)을 참조하고 있다.
                console.dir(A.__proto__);
                      
                // 선언된 A 함수 객체로 위임된 원형과 Function 생성자 함수 객체의 원형 비교(동일하다)
                console.dir(A.__proto__ === Function.prototype); // true
                ```
                ![](http://mohwa.github.io/blog/assets/images/posts/20151012/prototype_2.png)		
            
          • JS Built-in 객체 중 하나인 Array 객체

              var fruits = ["Apple", "Banana"];
                        
              // 배열의 길이를 반환한다.
              console.log(fruits.length); // 2
            
          • 객체 원형 및 위임 과정

            ```javascript
            // Object 생성자 함수 객체로 새로운 객체를 생성한다.
            var obj = new Object();
                
            // 생성된 새로운 객체
            console.dir(obj);
                
            // 새로운 객체로 위임된 Object 생성자 함수 객체의 원형
            console.log(obj.__proto__);
                
            // Object 생성자 함수 객체의 원형
            console.log(Object.prototype);
                
            // 새로운 객체로 위임된 원형과 Object 생성자 함수 객체의 원형 비교(동일하다)
            console.log(obj.__proto__ === Object.prototype); // true
                
            // 위임 과정을 통해 toString 메서드를 사용할 수 있다.
            console.dir(obj.toString);
            ```	
                  
            ![](http://mohwa.github.io/blog/assets/images/posts/20151012/prototype_1.png)		
            
    • 클래스 기반 언어는 보통 정적 언어를 말하며, JS 와 같은 동적 언어컴파일 시점이 아닌 런타임 시점에서 정적 언어가 다루는 특정 일(자료형 검사, 함수 오버로드, 동적 디스패치 등)들을 수행하게된다.

      • 정적/동적 언어란?

        • 정적언어<p>

          • 컴파일 시점에서 자료형 검사가 이루어진다.<p>

          • 컴파일 시점의 자료형 검사로 인해 런타임 시점에서는 자료형에 대한 많은 오류를 줄일 수 있다.(단 컴파일 시점에서 결정될 수 있는 자료형 정보만이 평가(검사)된다)<p>

          • 컴파일 시점에서의 자료형 검사를 반복할 필요가 없기때문에, 전체 프로그램 실행 시간이 줄어든다.<p>

        • 동적언어

          • 런타임 시점에서 자료형 검사가 이루어진다.<p>

          • 런타임 시점의 자료형 검사로 인해 자료형에 대한 런타임 오류가 발생할 수 있다.(빈도수가 생각보다 많을수있다)<p>

          • 모든 런타임 객체가 자료형에 대한 정보를 가지고 있으며, 이를 통해 함수 오버로드, 동적 디스패치 등을 수행할 수 있다.(동적 언어가 가지는 유연성)<p>

          • 변수는 모든 자료형을 가질 수 있다.<p>

            • JS 동적 타이핑<p>

              • 자바스크립트는 느슨한 타입 (loosely typed) 언어, 혹은 동적 (dynamic) 언어이다. 그 말은, 변수의 타입을 미리 선언할 필요가 없다는 뜻이다. 타입은 프로그램이 처리되는 과정에서 자동으로 파악될 것이다. 또한 그 말은 같은 변수에 여러 타입의 값을 넣을 수 있다는 뜻이다.<p>
          • 자바스크립트의 자료형<p>

          • Go 언어란? 정적 타입과 동적 타입에 대한 이야기

          • 런타임 시점에서 자료형 검사가 이루어진다.

              ``` javascript
                  
              // global execution context
                          
              // 원시 타입인 string 타입을 할당한다.
              var x = 'str';
                  
              // 원시 타입인 number 타입을 할당한다.
              x = 1;
                  
              // object 타입을 할당한다.
              x = {};
                  
              console.dir(x); // Object
              console.dir(typeof x); // object
                    
              ```
            
          • 런타임 시점의 자료형 검사로 인해 자료형에 대한 런타임 오류가 발생할 수 있다.

            ```javascript
                  
              var num = '1';
                  
              try {
                num.toFixed();
              }
              catch (e){
                // runtime error
                console.log(e.message); // num.toFixed is not a function
              }
                  
            ```
            
          • 모든 런타임 객체가 자료형에 대한 정보를 가지고 있으며, 이를 통해 함수 오버로드, 동적 디스패치 등을 수행할 수 있다.

            • JS 는 기본적으로 함수 오버로드를 지원하지 않으며, 아래와 같은 방법으로 구현 가능하다.<p>

                        
              // 함수 오버로드 구현
              function A(){
                        
                var args = arguments;
                        
                if (args.length === 1){
                  console.log(1); // 1
                }
                else if (args.length === 2){
                  console.log(2); // 2
                }
              };
                        
              A(1); // 1
              A(1, 2); // 2
                          
              

    2. 프로토타입 언어에서 객체를 생성하는 두 가지 방법

    • 무에서 객체를 생성하는 방법(원형 객체가 없는 상태에서 객체를 생성하는 방법)

            // 원형 객체가 없는 상태에서 객체를 생성하는 방법(일부 브라우저를 통해 아래와 같은 무형 객체를 구현할 수 있다)
            var instance = {};
            instance.__proto__ = null;
      
            console.dir(instance); // Object
            console.log(typeof instance); // object
      

    • 유에서 객체를 생성하는 방법(원형 객체가 존재하는 상태에서 객체를 생성하는 방법)

            // 원형 객체가 존재하는 상태에서 객체를 생성하는 방법(일반적인 위임 과정을 거친 객체)
            var instance = {};
      
            console.dir(instance); // Object
            console.log(typeof instance); // object
      

    • 보통 프로토타입 기반 언어에는 Object 객체(Master Object)가 존재하며, 이 객체의 원형에는 모든 객체가 공통적으로 필요한 특징(속성, 메서드)들이 정의되어있다.

        // A 함수 객체를 선언한다.
        function A(){
      
        }
      
        console.dir(A.constructor.__proto__.__proto__); // Object.prototype
      
        var obj = new Object();
      // 나를 만든 생성자 함수 객체의 원형
        console.dir(obj.__proto__); // Object.prototype
        console.dir(Object.prototype); // Object.prototype
      

    3. 위임 과정에 대해

    • JS는 프로토타입 기반 언어의 특징인 위임 과정을 따른다.

    • 모든 위임 과정은 런타임 시점에서 이루어진다.

    • 위임이란 객체들간의 원형 복제 과정을 말한다.

    • 위임된 객체 원형은 값(value)이 아닌 참조 값(reference of value)을 갖는다.

    • 위임된 객체 원형은 해당 객체의 특징(속성, 메서드)들을 공유하기위해 사용된다.

      • A 함수 객체에 대한 위임 결과.

          // A 함수 객체를 선언한다.
          function A(){
        
          }
        
          console.dir(A);
        
        
      • A: 선언된 A 함수 객체

      • A.prototype: 나를 통해 생성될 객체의 원형

        ```javascript
        console.log(A.prototype === new A().__proto__); // true
        ```
        
      • A.__proto__: 나를 만든 생성자 함수 객체의 원형

        ```javascript
        console.log(A.__proto__ === Function.prototype); // true
        ```
        
      • A.constructor: 나를 만든 생성자 함수 객체

        ```javascript
        console.log(A.constructor === Function); // true
        ``` ![](http://mohwa.github.io/blog/assets/images/posts/20151012/prototype_4.png)		
        
        • objA 객체에 대한 위임 결과.

            // A 함수 객체를 선언한다.
            function A(){
          
            }
          
            // A 생성자 함수 객체를 통해 새로운 객체를 생성한다.
            var objA = new A();
          
            console.dir(objA);
          
      • objA: 생성된 objA 객체

      • objA.__proto__: 나를 만든 생성자 함수 객체의 원형

          console.log(objA.__proto__ === A.prototype); // true
        
      • A.constructor: 나를 만든 생성자 함수 객체

          console.log(objA.constructor === A); // true
        

    • 위임받은 자식 객체는 부모 객체의 원형을 참조하고 있기 때문에, 자식 객체로 부터 부모 객체의 원형이 변조될 수 있다.(이로인해 아주 위험한 상황이 연출될 수 있다)

      • 부모 객체: A 생성자 함수 객체
      • 자식 객체: objA 변수가 참조하는 객체(new A)

        
          // A 함수 객체를 선언한다.
          function A(){
        
          }
        
          var objA = new A;
        
          // 자식 객체를 통해 부모 객체의 원형(A.prototype)을 변조한다.
          // objA.__proto__ === A.prototype
          objA.__proto__.getConstructor = function(){
              return this.constructor;
          }
        
          console.dir(A.prototype.getConstructor()); // A 생성자 함수 객체
        

    • 위임 받은 자식 객체는 원하는 특징(속성, 메서드)에 도달하기위해, 각 객체들이 가진 원형을 연속적으로 따라가 찾아내게된다.

        // parent 객체는 id 속성 값을 가지고 있다.
        var parent = {
            id: 'parentId'
        };
      
        // child1 객체는 name 속성 값을 가지고 있다.
        var child1 = {
            name: 'child1Name'
        };
      
        // child2 객체는 각 속성 값을 반환받는 get 접근자 메서드를 가지고 있다.
        var child2 = {
            getId: function(){
                return this.id;
            },
            getName: function(){
                return this.name;
            }
        };
      
        // parent 객체의 모든 특징(속성, 메서드)들을 child1 객체 원형으로 위임한다.
        child1.__proto__ = parent;
        // child1 객체의 모든 특징(속성, 메서드)들을 child2 객체 원형으로 위임한다.
        child2.__proto__ = child1;
      
        console.dir(child2);
        console.log(child2.getId()); // parentId
        console.log(child2.getName()); // child1Name
      

        // parent 객체는 id 속성 값을 가지고 있다.
        var parent = {
            id: 'parentId'
        };
      
        // child1 객체는 name 속성 값을 가지고 있다.
        var child1 = {
            name: 'child1Name'
        };
      
        // child2 객체는 각 속성 값(id, name)과 그것들을 반환하는 get 접근자 메서드를 가지고 있다.
        var child2 = {
            id: 'child2Id',
            name: 'child2Name',
            getId: function(){
                return this.id;
            },
            getName: function(){
                return this.name;
            }
        };
      
        // parent 객체의 모든 특징(속성, 메서드)들을 child1 객체 원형으로 위임한다.
        child1.__proto__ = parent;
        // child1 객체의 모든 특징(속성, 메서드)들을 child2 객체 원형으로 위임한다.
        child2.__proto__ = child1;
      
        console.dir(child2);
        console.log(child2.getId()); // child2Id
        console.log(child2.getName()); // child2Name
      

    • 또한, 프로토타입 검색 범위는 동적으로 변경될 수 있다.

        var instance = {};
      
        function extend(){
            instance.__proto__ = {
                x: {},
                y: {},
                z: {}
            };
        }
      
        // 런타임 시점에서 객체가 확장된다.
        extend();
        console.dir(instance);
      

    4. 연쇄 과정에 대해

    • 순수 프로토타입연쇄적 프로토타입이라고도 한다.

    • 연쇄란 객체들간의 원형 복제 과정을 말한다.

    • 연쇄된 객체 원형은 참조 값(reference of value)이 아닌 원본으로부터 복제된 객체 값(value)을 갖는다.

    • 연쇄된 자식 객체는 원본 객체로부터 복제된 원형을 참조하기 때문에, 자식 객체를 통해 원본 객체의 특징들이 변조될 수 없다.

    • 연쇄된 자식 객체는 원하는 특징(속성, 메서드)에 도달하기위해, 각 객체들이 가진 원형을 연속적으로 따라가 찾아내게된다.

        // 원본 객체
        var instance1 = {
            id: 'yanione'
        };
      
        // 자식 객체
        var instance2 = {
            name: 'mohwa'
        };
      
        // 클론 함수
        function clone(obj){
      
            if (!obj || obj.constructor !== Object) return false;
      
            var clone = {};
      
            for (var n in obj){
                clone[n] = obj[n];
            };
      
            return clone;
        };
      
        // 원본 객체를 복제한다.
        var cloneInstance = clone(instance1);
      
        // 복제된 원본 객체를 자식 객체의 원형으로 연쇄한다.
        instance2.__proto__ = cloneInstance;
      
        // 자식 객체가 연쇄받은 원본 객체의 속성 값을 변경한다.
        instance2.__proto__.id = 'mohwa';
      
        // 이전 위임 과정과 달리 자식 객체로 인해 원본 객체의 원형이 변조되지 않는다.
        console.log(instance1.id); // yanione
      
    • 연쇄 방식의 프로토타입 검색 범위는 정적(연쇄 시점에 의해)으로 고정된다.

        // 원본 객체
        var instance1 = {
            id: 'yanione'
        };
      
        // 자식 객체
        var instance2 = {
            name: 'mohwa'
        };
      
        // 클론 함수
        function clone(obj){
      
            if (!obj || obj.constructor !== Object) return false;
      
            var clone = {};
      
            for (var n in obj){
                clone[n] = obj[n];
            };
      
            return clone;
        };
      
        // 원본 객체를 복제한다.
        var cloneInstance = clone(instance1);
      
        // 복제된 원본 객체를 자식 객체의 원형으로 연쇄한다.
        instance2.__proto__ = cloneInstance;
      
        // 원본 객체를 동적으로 확장시킨다.
        instance1.getId = function(){
            return this.id;
        }
      
        // 자식 객체는 연쇄 시점의 복제된 원본 객체의 원형을 참조하고 있기때문에, 동적으로 확장된 원본 객체의 특성을 갖지 못한다.
        console.log(instance2.getId); // undefined
      

    Read more


  • generator 

    1. 문서 내용에 대해

    • 이 문서에서는 Yeoman 을 통해 자신만의 app generator 모듈을 생성하는 방법에 대해 알아볼 것이다.

    • Yeoman공식 홈페이지를 통해, 이를 시작하기 위한 내용을 제공하고있다.

    • 이 문서의 내용은 MAC 환경을 기준으로 작성되어있다.

    2 app generator 개발 환경 구축

    • generator-generator 모듈은 사용자가 자신만의 app generator 모듈을 개발할때, 그 기반 설계를 도와주는 Yeoman generator 모듈 중 하나이다.

      • 반드시 이 구조를 따라갈 필요는 없겠지만, generator-generator 모듈은 어차피 기본 골격만 제공하므로, 해당되는 부분에 대해서는 동일하게 따라가도 좋을 듯 하다.
    • generator-generator 모듈을 설치한다.

        sudo npm install -g generator-generator
      
    • 설치된 generator-generator 모듈을 통해 생성할 app generator 모듈의 **기반**을 생성한다.

         yo generator
      

    • 생성할 app generator 모듈의 base-name 을 위와 같이 입력 후 설치를 완료하면, 입력한 base-name 을 기준으로 현재 위치에 app generator 모듈 폴더(./generator-cmtech)가 생성된다.

    • 생성된 app generator 모듈 폴더(./generator-cmtech) 이름은 아래와 같은 형식으로 생성되며, Yeoman 은 이후 yo [base-name] 명령 실행 시 이 base-name 이 기준이된 app generator 모듈 폴더를 File system 상에서 찾아 실행하게될것이다.

      • 생성된 app generator 모듈 폴더 이름: generator-base-name

      • app generator 모듈 설치 명령: yo base-name

    • 개발중인 app generator 모듈을 링크를 통해 설치한다.

      • 정확히 말하면 사용자 시스템global node module 위치에, 개발중인 app generator 모듈(./generator-cmtech) 폴더의 링크를 만들어, **npm** 모듈을 설치하는것과같은, 환경을 만들어주는것이다.

      • 먼저 global node module(/usr/local/lib/node_modules) 위치로 이동하여, 생성된 app generator 모듈 폴더를 링크 한다.

            // global node module 위치로 이동한다.
            cd /usr/local/lib/node_modules
              
            // app generator 모듈 폴더를 심볼릭 링크한다.
            sudo ln -s /Users/sgjeon/htdocs/gitrepos/generator-cmtech generator-cmtech
        

        그 다음 npm list 명령을 통해 app generator 모듈이 제대로 설치(링크)되었는지 확인해본다.

        확인되었다면, yo [base-name] 명령을 통해, app generator 모듈이 제대로 설치되는지 확인한다.

    3. app generator 개발 포인트

    • package.json 파일 설정

      • 아래는 app generator 모듈 폴더안의 package.json 파일 내용이다.

        ```javascript
        {
          "name": "generator-cmtech",
          "version": "0.0.0",
          "description": "cmtech generator",
          "license": "MIT",
          "main": "app/index.js",
          "repository": "mohwa/generator-cmtech",
          "author": {
          "name": "mucha",
          "email": "",
          "url": "https://github.com/mohwa"
          },
          "scripts": {
          "test": "mocha"
          },
          "files": [
          "generators"
          ],
          "keywords": [
          "yeoman-generator"
          ],
          "dependencies": {
          "yeoman-generator": "^0.19.0",
          "chalk": "^1.0.0",
          "yosay": "^1.0.2"
          },
          "devDependencies": {
          "mocha": "*"
          }
        }
        ```
        
      • name property 는 반드시 generator- 라는 접두사를 가져야한다.

        • 예: generator-cmtech
      • Yeoman 에서 제공하는 generator-page 에 listed 되기 위해서는 keywords property 와 description property 를 반드시 서술해야한다.

        • keywords property 에는 예제와 같이 “yeoman-generator” 를 할당해준다.
    • Folder tree

      • Yeoman 은 아래와 같은 두 가지 폴더 구조를 제공하고있다.

      • ./ 폴더 내부로 가용한 default generatorsub-generator 를 만들어내는 구조

          ├───package.json
          ├───app/
             └───index.js
          └───router/
            └───index.js
        
      • ./generators 폴더 내부로 가용한 default generatorsub-generator 를 만들어내는 구조(개인적으로 이 폴더 구조를 선호한다)

          ├───package.json
          └───generators/
            ├───app/
               └───index.js
            └───router/
              └───index.js
        
      • default generatorsub-generator 호출 방법

        • default generator 호출 방법

          • yo [base-name] 명령으로 실행하며, 이로인해 ./generators/app/ 디렉토리 안의 index.js 파일이 호출된다.

          • 예: yo cmtech

        • sub-generators 호출 방법

          • yo [base-name]:[sub-command] 명령으로 실행하며, 이로인해 ./generators/[sub-command]/ 디렉토리 안의 index.js 파일이 호출된다.

          • 예: yo cmtech:router

    • base generator 확장하기

      • yeoman-generator 모듈을 통해 base generator 를 생성할 수 있으며, 이것을 확장하여 자신만의 app generator 모듈 기능을 만들어낸다.

        ```javascript
            
        // app/index.js 내부
            
        // base generator 를 생성한다.
        var generators = require('yeoman-generator');
            
        // base generator 를 확장한다.
        module.exports = generators.Base.extend({
            
            constructor: function () {
            
            generators.Base.apply(this, arguments);
            
            // This makes `appRootFolder` a required argument.
            this.argument('appRootDir', { type: String, required: true });
            
            }
        });
        ```
        
    • Overwriting(기존 property 를 다시쓰는 행위) the constructor

      • 특정 generator 메서드들은 constructor function 내부에서만 호출해야한다. 만약 그렇지 않을경우, 해당 기능이 완벽히 수행되지 않을 수 있다.

      • 예를들어, 사용자가 Command Line 을 통해 입력한 arguments 를 처리하는 this.argument 메서드 호출 시, 해당 코드가 호출되는 **위치**에 따라 다른 **결과**를 반환되게된다.

      • 먼저 테스트위해 yo cmtech --help 명령을 실행한다.

          // cmtech generator 를 --help 옵션과 함께 실행한다.
          yo cmtech --help
        
      • argument 메서드가 constructor function 내부에서 호출된 경우.

          // base generator 를 확장한다.
          module.exports = generators.Base.extend({
              
              constructor: function () {
              
              generators.Base.apply(this, arguments);
              
              // This makes `appRootFolder` a required argument.
              this.argument('appRootDir', { type: String, required: true });
              
              }
          });
        

        Yeomanarguments 에 대한 상세 도움말을 제공해준다.

        argument 메서드가 constructor function 외부에서 호출된 경우.

          // base generator 를 확장한다.
          module.exports = generators.Base.extend({
              
              initializing: function(){
              this.argument('appRootDir', { type: String, required: true });
              }
          });
        

        arguments 에 대한 도움말이 제공되지 않는다.

    • GENERATOR RUNTIME CONTEXT

      • The run loop

        • Yeomanrun loop 라는 queue system 을 가지며, 이것은 실행하려는 메서드 **그룹**에 대한 우선 순위를 제공해준다.

          • 또한 run loop 다루기위해 Grouped-queue 라는 모듈을 사용하고있다.
        • 우선 순위Yeoman 이 제공하는 특별한 프로토타입 **메서드 이름**(priority name)으로만 사용된다.

          • Yeoman 이 제공하는 priority name 리스트는 아래와 같다.

        • priority name 일 경우.

            'use strict';
            var yeoman = require('yeoman-generator');
            var chalk = require('chalk');
            var yosay = require('yosay');
                  
            module.exports = yeoman.generators.Base.extend({
                  
              initializing: {
              init: function() {
                console.log('call by init method 1');
              },
              end: function(){
                console.log('call by end method 2');
              }
              }
            });
          
        • 정의된 메서드 그룹이 전부 실행된다.

        - <span style="color:#c11f1f">priority name</span> 이 아닐경우.
      
            ```javascript
            'use strict';
            var yeoman = require('yeoman-generator');
            var chalk = require('chalk');
            var yosay = require('yosay');
          
            module.exports = yeoman.generators.Base.extend({
          
              custom_method: {
              init: function() {
                console.log('call by init method 1');
              },
              end: function(){
                console.log('call by end method 2');
              }
              }
            });
          
            ```
      	
            정의된 **메서드**가 실행되지 않는다.
          
            ![](http://mohwa.github.io/blog/assets/images/posts/20151002/yeoman_9.jpg?1)
      
            또한 <span style="color:#c11f1f">priority name</span> 이 아닐경우, 아래와 같이 **Object** 가 아닌 **Function** 타입으로 정의해야한다.
          
            ```javascript
            'use strict';
            var yeoman = require('yeoman-generator');
            var chalk = require('chalk');
            var yosay = require('yosay');
          
            module.exports = yeoman.generators.Base.extend({
                custom_method: function(){
                console.log('call by custom_method method');
                }
            });
          
            ```
            ![](http://mohwa.github.io/blog/assets/images/posts/20151002/yeoman_10.jpg?1)
          
            [http://yeoman.io/authoring/running-context.html](http://yeoman.io/authoring/running-context.html)
      
    • Template 엔진 사용하기

      • Yeomanejs template 엔진을 사용하며, copyTpl 메서드와 같은 템플릿 관련 메서드들을 제공하고 있다.

        • http://yeoman.io/generator/actions_actions.html

        • 아래 코드는 메서드 사용에 대한 간단한 예제이며, .html 파일외에, APP 을 구성하는 기반 파일인 _package.json 또는 _gruntfile.js 와 같은 파일에도 동일하게 적용할 수 있다.

            generators.Base.extend({
                writing: function () {
                this.fs.copyTpl(
                  this.templatePath('index.html'),
                  this.destinationPath('public/index.html'),
                  { title: 'Templating with Yeoman' }
                );
                }
            });
          
      • template 엔진을 통해 아래와 같이 출력된다.

          ```javascript
          <html>
            <head>
            <title>Templating with Yeoman</title>
            </head>
          </html>
          ```
        
      • 추가적으로 의존성을 관리하는 파일인 _bower.json 파일에 적용된 내용이다.

          ```javascript
          <% var ngVer = "1.2.26" %>
          {
            "name": "<%= env.appName %>",
            "description": "<%= env.appName %> package manager",
            "homepage": "http://www.cmt-korea.com/",
            "author": {
            "name": "sgjeon"
            },
              
            "ignore": [
            "**/.*",
            "node_modules",
            "bower_components"
            ],
            "dependencies": {
            },
            "devDependencies": {
            "angular": "<%= ngVer %>",
            "angular-animate": "<%= ngVer %>",
            "angular-cookies": "<%= ngVer %>",
            "angular-route": "<%= ngVer %>",
            "angular-resource": "<%= ngVer %>",
            "angular-sanitize": "<%= ngVer %>",
            "requirejs": "2.1.14",
            "jquery": "2.1.1",
            "malihu-custom-scrollbar-plugin": "3.0.8",
            "jquery-ui": "1.11.2",
            "json3": "3.3.2",
            "linqjs": "",
            "xml2json": "",
            "purl": "2.3.1",
            "jquery-mousewheel": "3.0.6",
            "socket.io-client": "1.3.5",
            "console.image": "",
            "enquire": "2.1.2",
            "angular-local-storage": "0.1.5",
            "matchMedia": "0.2.0",
            "jquery.browser": "0.0.7"
            }
          }
          ```
        
    • 전역 configurations 파일 관리하기

      • Yeoman 은 숨김 파일인 .yo-rc.json 파일을 통해 전역 configurations 을 관리할 수 있으며, 또 그것을 관리하기 위한 Yeoman Storage API 를 제공하고있다.

      • 아래는 기본적인 .yo-rc.json 파일 구조이다.

        ```javascript
        {
          "generator-cmtech": {
            "key": "value"
          }
        }
        ```
        

    4. 정리하며

    • 아래 URL 은 현재 개발중인 사이트(AngularJS 사용)의 app generator 초기 버전이며, 설계시 참고할 수 있을 듯하여 공유드립니다.(현재는 테스트 버전입니다)

    Read more