문제

글쎄, 나는 이것이 어떤 식 으로든 가능하다는 것을 알아 내려고 노력했다. 코드는 다음과 같습니다.

a=function(text)
{
   var b=text;
   if (!arguments.callee.prototype.get)
      arguments.callee.prototype.get=function()
    {
         return b;
    }
    else
      alert('already created!');
}

var c=new a("test");  // creates prototype instance of getter
var d=new a("ojoj");  // alerts already created
alert(c.get())        // alerts test 
alert(d.get())        // alerts test from context of creating prototype function :(

보시다시피 프로토 타입 게터를 만들려고했습니다. 무엇을 위해? 당신이 다음과 같이 쓰면 :

a=function(text)
{
    var b=text;
    this.getText=function(){ return b}
}

... 모든 것이 괜찮아야합니다. 그러나 실제로 객체를 만들 때마다 - 메모리를 사용하는 getText 함수를 만듭니다. 메모리에 똑같이 할 수있는 하나의 프로토 타입 기능을하고 싶습니다 ... 어떤 아이디어라도?

편집하다:

나는 Christoph가 제공 한 솔루션을 시도했으며 지금은 알려진 솔루션으로 보인다. 상황에서 가치를 검색하기 위해 ID 정보를 기억해야하지만 전체 아이디어는 나에게 좋습니다 :) ID는 기억해야 할 한 가지 일 뿐이며, 다른 모든 것은 한 번 기억에 저장 될 수 있습니다. 실제로 이런 식으로 많은 개인 회원을 저장하고 언제든지 하나의 ID 만 사용할 수 있습니다. 실제로 이것은 나를 만족시킨다 :) (누군가가 더 나은 아이디어를 얻지 않는 한).

someFunc = function()
{
  var store = new Array();
  var guid=0;
  var someFunc = function(text)
  {
    this.__guid=guid;
    store[guid++]=text;
  }

  someFunc.prototype.getValue=function()
  {
    return store[this.__guid];
  }

  return someFunc;
}()

a=new someFunc("test");
b=new someFunc("test2");

alert(a.getValue());
alert(b.getValue());
도움이 되었습니까?

해결책

JavaScript는 전통적으로 속성 숨기기 ( '개인 회원')를위한 메커니즘을 제공하지 않았습니다.

JavaScript가 어휘 스코핑되므로 생성자 기능을 '개인 멤버'의 폐쇄로 사용하고 생성자에서 메소드를 정의하여 항상 객체 당 수준에서이를 시뮬레이션 할 수 있지만 이는 생성자의 프로토 타입 속성.

물론이 문제를 해결하는 방법이 있지만 권장하지는 않습니다.

Foo = (function() {
    var store = {}, guid = 0;

    function Foo() {
        this.__guid = ++guid;
        store[guid] = { bar : 'baz' };
    }

    Foo.prototype.getBar = function() {
        var privates = store[this.__guid];
        return privates.bar;
    };

    Foo.prototype.destroy = function() {
        delete store[this.__guid];
    };

    return Foo;
})();

이것은 '개인'속성을 다른 개체에 저장합니다. Foo 사례. 전화하십시오 destroy() 객체가 완료된 후에 : 그렇지 않으면 메모리 누출을 만들었습니다.


2015-12-01 편집 : ecmascript6은 수동 객체 파괴가 필요하지 않은 개선 된 변형을 만듭니다. 약점 또는 바람직하게는 a 상징, 외부 상점의 필요성을 모두 피하십시오 :

var Foo = (function() {
    var bar = Symbol('bar');

    function Foo() {
        this[bar] = 'baz';
    }

    Foo.prototype.getBar = function() {
        return this[bar];
    };

    return Foo;
})();

다른 팁

프로토 타입의 방법은 JavaScript에 존재하는 "개인"멤버에 액세스 할 수 없습니다. 당신은 일종의 특권 액세서가 필요합니다. 당신이 선언하고 있기 때문에 get 어휘를 볼 수있는 곳 b, 그것은 항상 무엇을 반환 할 것입니다 b 창조에 있었다.

Christoph의 근무자들에게 큰 영감을받은 후, 나는 몇 가지 향상된 개념을 제공하는 약간 수정 된 개념을 생각해 냈습니다. 다시 말하지만,이 솔루션은 흥미롭지 만 반드시 권장되는 것은 아닙니다. 이러한 개선 사항에는 다음이 포함됩니다.

  • 더 이상 생성자에서 설정을 수행 할 필요가 없습니다.
  • 인스턴스에 공개 안내서를 저장할 필요가 없음
  • 구문 설탕을 추가했습니다

본질적으로 여기서 트릭은 인스턴스 객체 자체를 관련 개인 객체에 액세스하는 열쇠로 사용하는 것입니다. 일반적으로 키는 문자열이어야하므로 일반 물체에서는 불가능합니다. 그러나 나는 표현이라는 사실을 사용하여 이것을 달성 할 수있었습니다. ({} === {}) 보고 false. 다시 말해서 비교 연산자 ~할 수 있다 고유 한 객체 인스턴스를 식별하십시오.

간단히 말해서, 우리는 두 배의 배열을 사용하여 인스턴스와 관련 개인 개체를 유지할 수 있습니다.

Foo = (function() {
    var instances = [], privates = [];

    // private object accessor function
    function _(instance) {
        var index = instances.indexOf(instance), privateObj;

        if(index == -1) {
            // Lazily associate instance with a new private object
            instances.push(instance);
            privates.push(privateObj = {});
        }
        else {
            // A privateObject has already been created, so grab that
            privateObj = privates[index];
        }
        return privateObj;
    }

    function Foo() {
        _(this).bar = "This is a private bar!";
    }

    Foo.prototype.getBar = function() {
        return _(this).bar;
    };

    return Foo;
})();

당신은 알게 될 것입니다 _ 위의 기능. 이것은 개인 대상을 잡을 수있는 액세서 기능입니다. 그것은 게으르게 작동하므로 새 인스턴스로 호출하면 새로운 개인 객체를 즉시 생성합니다.

복제하고 싶지 않다면 _ 모든 수업에 대한 코드는 공장 기능 안에 래핑하여이를 해결할 수 있습니다.

function createPrivateStore() {
    var instances = [], privates = [];

    return function (instance) {
        // Same implementation as example above ...
    };
}

이제 각 클래스마다 하나의 줄로 줄일 수 있습니다.

var _ = createPrivateStore();

다시, 당신은 있어야합니다 매우 조심합니다 이 솔루션을 사용하여 사용합니다 ~할 수 있다 구현하지 않으면 메모리 누출을 만듭니다. 필요할 때 파괴 기능을 호출하십시오.

일부 ES6 기술을 채택하는 최신 브라우저를 사용하면 사용할 수 있습니다. WeakMap 안내 문제를 해결하기 위해. 이것은 IE11 이상에서 작동합니다.

// Scope private vars inside an IIFE
var Foo = (function() { 
    // Store all the Foos, and garbage-collect them automatically
    var fooMap = new WeakMap();

    var Foo = function(txt) { 
        var privateMethod = function() { 
            console.log(txt); 
        };
        // Store this Foo in the WeakMap
        fooMap.set(this, {privateMethod: privateMethod}); 
    } 

    Foo.prototype = Object.create(Object.prototype); 
    Foo.prototype.public = function() { 
        fooMap.get(this).p(); 
     } 
     return Foo; 
 }());

 var foo1 = new Foo("This is foo1's private method");
 var foo2 = new Foo("This is foo2's private method");
 foo1.public(); // "This is foo1's private method"
 foo2.public(); // "This is foo2's private method"

WeakMap 참조를 저장하지 않을 것입니다 Foo 삭제되거나 범위가 떨어지면 개체를 키로 사용하므로 객체에 안내서를 첨부 할 필요가 없습니다.

개인적으로, 나는 가이드와 함께 솔루션을 좋아하지 않습니다. 왜냐하면 개발자는 매장 외에 그것을 선언하고 생성자에서 증가시킬 수 있기 때문입니다. 대규모 JavaScript 응용 프로그램에서 개발자는 그렇게하는 것을 잊을 수 있습니다.

나는 당신이 문맥 (이것)을 사용하여 개인 회원에게 액세스 할 수 있기 때문에 Peter의 대답을 거의 좋아합니다. 그러나 나를 귀찮게하는 한 가지는 개인 회원에 대한 접근이 AO (N) 복잡성으로 이루어진다는 사실입니다. 실제로 배열에서 객체의 색인을 찾는 것은 선형 알고리즘입니다. 이 패턴을 10000 회 주입 한 객체에 사용하려는 것을 고려하십시오. 그런 다음 개인 회원에게 액세스 할 때마다 100000 인스턴스를 반복 할 수 있습니다.

AO (1) 복잡성의 개인 상점에 액세스하기 위해서는 안내서를 사용하는 것 외에는 다른 방법이 없습니다. 그러나 Guid 선언 및 증분을 방해하지 않고 컨텍스트를 사용하여 개인 상점에 액세스하기 위해 Peters Factor Pattern을 다음과 같이 수정했습니다.

createPrivateStore = function () {
var privates = {}, guid = 0;

return function (instance) {
    if (instance.__ajxguid__ === undefined) {
        // Lazily associate instance with a new private object
        var private_obj = {};
        instance.__ajxguid__ = ++guid;
        privates[instance.__ajxguid__] = private_obj;
        return private_obj;
    }

    return privates[instance.__ajxguid__];
}

}

여기의 요령은 ajxguid 속성은 아직 처리되지 않았습니다. 실제로, 매장에 처음으로 접근하기 전에 수동으로 속성을 설정할 수는 있지만 마법의 해결책은 없다고 생각합니다.

실제 프라이버시가 과대 평가되었다고 생각합니다. 가상 개인 정보가 필요한 전부입니다. _PrivateIngifier의 사용은 올바른 방향으로의 단계라고 생각하지만 여전히 충분히 그리 멀지 않습니다. 왜냐하면 여전히 지능적인 팝업에 모든 _privateIndifiers의 목록이 표시되어 있기 때문입니다. 점점 더 나은 단계는 프로토 타입 및/또는 생성자 함수에 객체를 만들기 위해 사실상 개인 필드와 방법을 분리하기 위해

  // Create the object
  function MyObject() {}

  // Add methods to the prototype
  MyObject.prototype = {

    // This is our public method
    public: function () {
      console.log('PUBLIC method has been called');
    },

    // This is our private method tucked away inside a nested privacy object called x
    x: {
      private: function () {
        console.log('PRIVATE method has been called');
      }
    },

  }

// Create an instance of the object
var mo = new MyObject(); 

이제 코더가 "mo"를 입력 할 때. Intellisense는 공개 기능과 "x"만 보여줄 것입니다. 따라서 모든 개인 회원은 표시되지 않고 "X"뒤에 숨겨져 있으며 코더가 실수로 개인 회원에게 전화를 걸 수 없을 것입니다. 개인 회원을 만나기 위해. 이 방법은 또한 Intellisense 목록이 여러 개인 멤버 이름으로 어수선하여 단일 항목 "X"뒤에 숨겨지는 것을 피합니다.

나는이 스레드가 지금 정말로 늙었다는 것을 알고 있지만이 솔루션은 지나가는 사람에게 관심이 있다고 생각했습니다.

const Immutable = function ( val ) {
    let _val = val;

    this.$ = {
        _resolve: function () {
            return _val;
        }
    };
};
Immutable.prototype = {
    resolve: function () {
        return this.$._resolve();
    }
};

본질적으로 내부를 숨기고 있습니다 _val 조작 되고이 대상의 인스턴스를 불변으로 만드는 것입니다.

프로토 타입 체인에서 개인 메소드를 활성화하기위한 새로운 라이브러리를 만들었습니다.https://github.com/tremaynechrist/protectjs

예시:

var MyObject = (function () {

  // Create the object
  function MyObject() {}

  // Add methods to the prototype
  MyObject.prototype = {

    // This is our public method
    public: function () {
      console.log('PUBLIC method has been called');
    },

    // This is our private method, using (_)
    _private: function () {
      console.log('PRIVATE method has been called');
    }
  }

  return protect(MyObject);

})();

// Create an instance of the object
var mo = new MyObject();

// Call its methods
mo.public(); // Pass
mo._private(); // Fail
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top