2

다른 사람의 JavaScript 코드를 다시 고려했습니다.`prototype`과`new`에서 클로저와 노출 패턴으로 이동

전 :

function SomeObj(flag) { 
    var _private = true; 
    this.flag = (flag) ? true : false; 
    this.version="1.1 (prototype)"; 
    if (!this._someProperty) this._init(); 
      // leading underscore hints at what should be a 'private' to me 
    this.reset(); // assumes reset has been added... 
} 

SomeObj.prototype.reset = function() { 
    /* perform some actions */ 
} 

/* UPDATE */ 
SomeObj.prototype.getPrivate = function() { 
    return _private; // will return undefined 
} 

/* ...several other functions appended via `prototype`...*/ 

AFTER : 첫 번째 예는 어려운 보이는 나를 위해

var SomeObj = function (flag) { 
    var _private = true; 
    this.flag = (flag) ? true : false; 
    this.version = "2.0 (constructor)"; 

    this.reset = function() { 
     /* perform some actions */ 
    }; 

    /* UPDATE */ 
    this.getPrivate = function() { 
     return _private; // will return true 
    } 

    /* other functions and function calls here */ 
} 

특히 더 큰 맥락에서 읽을 수 있습니다. reset과 같은 메서드를 prototype 속성을 사용하여 추가하는 것은 스크립트의 어느 위치에서나 발생할 수 있으므로 제어가 덜한 것처럼 보입니다. 내 리팩토링 된 코드 (위의 두 번째 예제)는 나에게 훨씬 깔끔하게 보이므로 독점적이기 때문에 읽기가 쉽습니다. 변수 선언을 통해 개인 정보를 얻었지만 프로토 타입 체인의 가능성을 잃어 버렸습니다.

...

질문 : 첫째

  1. , 나는 내가 prototype를 전술에 의해 잃은 사람을 알고 관심, 또는의 손실에 더 큰 의미가있는 경우 프로토 타입 체인. This article은 6 세이지만, prototype 속성을 사용하면 클로저 패턴보다 훨씬 더 효율적이라고 주장합니다.

  2. 위의 두 예제는 여전히 new 연산자로 인스턴스화됩니다. 그들은 둘 다 '고전적'일 뿐이다. 결국 나는 심지어 모든 속성과 함수가 var으로 선언 된 모델로 옮겨 가고 싶습니다. 그리고 필요한 모든 속성과 메서드를 열어주는 객체를 반환 할 수있는 하나의 메서드가 있습니다. (폐쇄로 인해) 사적인 사람들에게 특권을 가지고있다.. 이런 식으로 뭔가 :

    var SomeObj = (function() { 
    
        /* all the stuff mentioned above, declared as 'private' `var`s */ 
    
        /* UPDATE */ 
        var getPrivate = function() { 
         return private; 
        } 
    
        var expose = function (flag) { 
         // just returns `flag` for now 
         // but could expose other properties 
         return { 
          flag: flag || false, // flag from argument, or default value 
          getPrivate: getPrivate 
         } 
        }; 
    
        return { 
         expose: expose 
        } 
    })(); // IIFE 
    
    // instead of having to write `var whatever = new SomeObj(true);` use... 
    var whatever = SomeObj.expose(); 
    

    상담자 '폐쇄 대 프로토 타입'해결에 StackOverflow에 대한 몇 가지 답변 (herehere 예를 들어)이 있습니다. 그러나 prototype 속성과 마찬가지로 new 연산자가 내 코드의 효율성과 가능성 손실 (예 : instanceof이 손실 됨)에 대한 의미가 무엇인지에 관심이 있습니다. 어쨌든 프로토 타입 상속을 사용하지 않을 경우 실제로 new 연산자를 사용하면 아무 것도 잃지 않습니까?

  3. 나는 내가 위에서 구체적인 요구하고있어 주어진 허용하고있어 경우 느슨한 질문 : prototypenew 정말 폐쇄보다 (당신은 그들이있을 것 같아요 무엇이든) 더 장점으로 갈 수있는 가장 효율적인 방법이 있다면 , 거기에 깔끔한 방식으로 그들을 작성하기위한 지침이나 디자인 패턴이 있습니까?

...

UPDATE :

expose이 때마다 새로운 개체를 반환하기 때문에 인스턴스가 일어나는 곳이하는 것으로

.이 개체가 SomeObj 클로저에 선언 된 메서드를 참조하는 곳에서이 점을 이해하면 덮어 쓰지 않는 한 모든 개체에서 동일한 메서드입니다. flag 변수의 경우 (지금 수정했습니다), 이는 expose의 인수에서 상속되거나, 기본값을 가지거나, 다시 캡슐화 된 기존의 메소드 또는 특성을 다시 참조 할 수 있습니다. 그래서 생성되는 객체의 인스턴스가 있고 거기에 어떤 상속 (더하기 다형성?)이 있습니다.

질문 2를 반복하십시오. 어쨌든 프로토 타입 상속을 사용하지 않을 경우 실제로 new 연산자를 사용하면 아무 것도 잃지 않습니까?

지금까지 많은 질문에 답변 해 주신 데 대해 감사드립니다.

+1

일부 토론에서 암시 된 방향으로 움직이는 것처럼 보였으므로이 블로그 항목을 읽으시 길 바랍니다. http://ejohn.org/blog/simple- class-instantiation/ –

+1

두 번째 예제에서'instanceof'를 사용할 수있는 능력을 잃지 않았으므로 일반 객체를 반환하는 세 번째 객체 만 특수 상속에 대해 테스트 할 수 없습니다. – Bergi

+0

@ MarkSchultheiss +1 기사 링크를 제공해 주셔서 감사합니다. 지금까지 유용한 점들. 그 반쯤은 사람들이 남긴 모든 관대 한 대답을 읽었습니다. – guypursey

답변

1

제 경험상 .prototype을 사용하지 않아서 잃는 유일한 것은 메모리입니다. 각 개체는 정의 된 함수 개체의 자체 복사본을 소유하게됩니다.

"작은"개체 수만 인스턴스화하려는 경우 큰 문제가되지는 않습니다.

특정 질문에 대해서는

:

  1. 링크 된 기사의 두 번째 의견은 매우 관련이있다. 작성자의 벤치 마크가 잘못되었습니다. 네 개의 내부 함수를 선언하는 생성자를 실행하는 오버 헤드를 테스트하고 있습니다. 이 아니며 해당 기능의 후속 성능을 테스트하는 것은이 아닙니다.

  2. "클로저 및 노출"코드 샘플은 OO가 아니며 일부 개인 변수가 포함 된 네임 스페이스 일뿐입니다. new을 사용하지 않기 때문에 객체를 인스턴스화하기를 원한다면 아무 소용이 없습니다.

  3. 나는 대답 할 수 없다 - "의존한다"는 대답은 좋은 대답이다. 질문에 의해

+1

OO 개념은 나에게 너무 엄격합니다. "closure and expose"메서드는 상속을 사용하지 않지만 개체와 메서드를 명확하게 처리하므로 "개체 지향"이 아닌 이유는 무엇입니까? 또한 상속과 인스턴스 생성은'Object.create'를 사용하여 여전히 달성 할 수 있습니다. – bfavaretto

+0

@bfavaretto 흠, 확실히 이상한 코드입니다. 처음에는 '플래그'상태를 설정할 방법이 없습니다. – Alnitak

+0

@bfavaretto 그리고 "OO가 아님"은 대부분 상속이 아니라'SomeObj'의 다중 인스턴스를 생성 할 수 없다는 것을 의미합니다. 단 하나의 인스턴스 만 있고'SomeObj.expose() '로 생성 된 변수는 같은 클로저를 공유하므로 같은 상태가됩니다. – Alnitak

0

질문 :

  1. 는 기본적으로 prototypereset 방법을 가지고하면 생성자의 모든 인스턴스는 방법의 동일한 복사본을 공유하는 것을 의미합니다. 생성자 내부에 로컬 메소드를 생성하면 인스턴스 당 메소드의 복사본 하나가 생성되어 더 많은 메모리를 사용하게됩니다 (많은 인스턴스가있는 경우 문제가 될 수 있습니다). 그 외에는 두 버전이 동일합니다. function SomeObj에서 var SomeObj = function으로 변경하는 것은 SomeObj이 상위 범위에서 어떻게 상승하는지에 따라 다릅니다. 당신은 "변수 선언을 통해 프라이버시를 얻었습니다."라고 말했지만, 거기에 어떤 사적인 변수도 보지 못했습니다.

  2. 언급 한 IIFE 접근법을 사용하면 을 확인할 수 없게됩니다.

  3. 이 질문에 대한 답변이 확실하지 않지만 Object.create도 있습니다. 여기서도 여전히 프로토 타입을 설정할 수 있지만 new 키워드는 제거 할 수 있습니다. 당신은 생성자를 갖는 능력을 잃어 버린다.

+0

답변 해 주셔서 감사합니다. 당신은 두 번째 예에서 사적인 변수를 볼 수 없다는 것이 옳았습니다. 나는 지금 하나를 추가했고, 비교할 수 있도록 첫 번째와 세 번째 예제와 비슷한 것을 추가했습니다. – guypursey

1
내가 prototype을 전술로 잃은 그 밖의 무엇

?

누군가가 대답을 제공 할 수 있지만 적어도 한 번 제공 할 것입니다. prototype를 사용하는 적어도 두 가지 이유가 있습니다 :

    prototype 방법은 정적으로 사용할 수있는 개체의 구성원이이 모든 생성됩니다한다는 뜻
  1. 그들은 한 번만

방법을 만들기 생성

  • 객체의 인스턴스. 객체 당 메모리가 많아 지므로 객체 생성 속도가 느려지므로 효율성이 떨어집니다. 사람들은 prototype 메서드는 클래스 메서드와 비슷하지만 멤버 메서드는 개체 메서드와 비슷하지만 프로토 타입 체인의 메서드는 여전히 개체 인스턴스를 사용할 수 있기 때문에 매우 잘못된 것입니다.

    당신은 객체 자체 프로토 타입을 정의 할 수 있습니다, 그래서 당신은 더 나은 구문을했습니다 (하지만 모두 다른 아니다) : 그것은 나에게 유효 덜 제어 보인다

    SomeObj.prototype = { 
        method1: function() {}, 
        method2: function() {} 
    } 
    

    귀하의 인수 것이다. 나는 두 개의 블럭이 객체 생성에 관여하는 것이 이상하다는 것을 알게된다. 그러나 어쨌든 누군가 다른 사람의 프로토 타입을 덮어 쓰는 것을 막는 것이 아무것도 없다는 점에서 약간의 가짜입니다. 당신은 단지 {} 표기를 즉석에서 특정 개체의 인스턴스를 생성 할 거라면 new

    을 상기

    //Your code 
    var SomeObj = function (flag) { //... 
    
    //Sneaky person's code 
    delete SomeObj.reset; 
    SomeObj.prototype.reset = function() { /* what now? */ } 
    

    , 어쨌든 new를 사용에서 정말 다른 아니다. 클래스 (function) 정의에서 동일한 객체의 여러 인스턴스를 만들려면 new을 사용해야합니다. 이는 객체 지향 프로그래밍 언어에 적용되기 때문에 드문 현상이 아니며 재사용과 관련이 있습니다.

    현재 응용 프로그램의 경우이 방법이 유용 할 수 있습니다. 그러나 컨텍스트간에 재사용 할 수있는 멋진 플러그인을 생각해 내면 짜증나는 결과를 낳을 수 있습니다. 나는 당신이 require.js과 같은 것을 찾고 있다고 생각하는데, require 함수로 가져올 수있는 "모듈"을 정의 할 수 있습니다. define 함수 클로저 내에 모듈을 정의하면 어쨌든 생성자와 프로토 타입 정의를 함께 묶어 둘 수 있으며 그 모듈을 가져올 때까지 아무도 다른 모듈을 터치 할 수 없습니다. 그들은 상호 배타적이지 prototype

    폐쇄 대의

    장점 :

    var attachTo = {}; 
    ;(function (attachTo, window, document, undefined) { 
        Plugin = function() { /* constructor */ }; 
        Plugin.prototype = { /* prototype methods */ }; 
    
        attachTo.plugin = Plugin; 
    })(attachTo, window, document); 
    var plugin = new (attachTo.plugin); 
    

    http://jsfiddle.net/ExplosionPIlls/HPjV7/1/

  • +0

    철저한 답변을 보내 주셔서 감사합니다. 나는 아직도 당신이 쓴 것을 파싱하고 있지만 코드를 덮어 쓰는 비열한 사람에 관한 당신의 요점은 나에게 일어났다. 누군가가 코드를 작성하여 프로토 타입과 간섭을 일으킬 수도 있습니다. 사고 (또는 비공개)를 이런 식으로 방지하는 방법을 알고 계십니까? 아니면 다음과 같이 해석 된 언어를 사용하는 것입니다. 자바 스크립트? 프로토 타입을 "보호"할 수 있습니까? – guypursey

    +0

    @guypursey 해석과는 아무 상관이 없습니다. Java에서 Reflection을 사용하여 개인 멤버에 액세스하고 메소드를 덮어 쓸 수 있습니다. 누군가 의도하지 않은 사용으로 우발적으로 이런 일을하게 될지 의심 스럽습니다. 귀하의 API. 프로토 타입을 "보호"하는 것은 불가능하거나 반드시 바람직한 것은 아닙니다. –

    +0

    나는 콘솔에 대한 액세스가 해석되는 JavaScript 코드가 특히 취약하다는 것을 알았지 만 컴파일 된 코드 (예 : Java)는 같은 방식으로 취약하지 않습니다. 방법에 의한 반사에 대한 흥미로운 점. 나는 Java로 (얼마전) 그걸 가지고 놀았지만 메소드를 호출하기 위해서만 사용했다. 나는 그것들을 덮어 쓰거나 사적인 멤버들에게 접근하는 것이 가능하다는 것을 몰랐다. 학문적 의미만으로도 JavaScript의 '프로토 타입'을 '보호'하는 것에 대해 더 많이 듣고 싶습니다. – guypursey

    1

    답변 :

    1. 당신은 이미이 질문에 대답 : 당신 느슨한 프로토 타입 체인. (실제로는 풀리지 않지만 프로토 타입은 항상 비어있게됩니다.)그 결과는 다음과 같습니다.

      • 각 인스턴스에 대해 메소드가 작성되기 때문에 약간의 성능/메모리 영향이 있습니다. 그러나 자바 스크립트 엔진에 많이 의존하기 때문에 많은 양의 객체를 만들어야하는 경우에만 걱정해야합니다.

      • 프로토 타입을 수정하여 원숭이 패치 인스턴스를 만들 수 없습니다. 커다란 문제는 아니므로 그 일을하는 것이 유지 보수의 악몽이됩니다.

    2. 나 귀하의 질문에 작은 현학적 보정을하자 : 폐쇄의 개념은 프로토 타입 기반 언어에 직교 사실 "폐쇄 대 프로토 타입"의 문제가되지 않습니다.

      질문은 객체를 만드는 방법과 관련이 있습니다. 매번 0에서 새 객체를 정의하거나 프로토 타입에서 복제합니다.

      함수를 사용하여 범위를 제한하는 방법을 보여주는 예제는 JavaScript에서 일반적인 방법이며 프로토 타입을 사용하기로 결정한 경우에도 계속 수행 할 수 있습니다. 예를 들어 :

      당신이 모듈화에 대해 고민하는 경우에
      var SomeObj = (function (flag) { 
      
          /* all the stuff mentioned above, declared as 'private' `var`s */ 
      
          var MyObj = function() {} 
          MyObj.prototype = { 
           flag: flag, 
           reset: reset 
          }; 
      
          return { 
           expose: function() { return new MyObj(); } 
          } 
      })(); 
      

      는, AMD (비동기 모듈 정의)이라는 기술을 구현 한 것입니다 requirejs에 봐. 어떤 사람들은 AMD를 좋아하지 않고 어떤 사람들은 그것을 좋아합니다. 저의 경험은 긍정적이었습니다. 브라우저 용 모듈 식 자바 스크립트 앱을 만드는 것이 많은 도움이되었습니다.

    3. 가 쉽게 프로토 타입과 당신의 인생을 몇 가지 라이브러리입니다 composejs, dejavu, 그리고 내 자신의 barman (예 뻔뻔한 자기 홍보,하지만 당신은 객체의 정의를 다루는 방법을 볼 수있는 소스 코드에 볼 수).

      패턴 정보 : 팩토리 메소드을 사용하여 객체 인스턴스화를 쉽게 숨길 수 있으므로 new을 사용하여 내부적으로 프로토 타입을 복제 할 수 있습니다.