How to get the encapsulated value in the prototype?

What it looks like:

function A(a,b){ this.a = a; this.b = b; var arr = [a,b]; } A.prototype.A1 = function(){ console.log(this.a); } A.prototype.A2 = function(){ console.log(this.arr); } var a1 = new A(1,2); a1.A1();//1 a1.A2();//undefined 

How to use arr in prototype?

  • 3
    no way. This is impossible - Grundy
  • one
    what call / apply are we talking about if the answer to the question is: how to get a locally declared variable? one answer - no way. - Grundy

8 answers 8

arr in this code is a local variable.

Access to a local variable can only be done inside the function in which the variable is declared.

Or in the internal functions.

 function A(a,b){ this.a = a; this.b = b; var arr = [a,b]; function B(){ console.log('B', arr); // доступно } console.log('A', arr); // доступно } A.prototype.C = function (){ /* arr недоступен */ } 

Thus, it is impossible to use the local variable arr somewhere other than the function A

    I recommend using Symbol to implement more or less private members of the "class".

     var A = (function() { var arrKey = Symbol(); A.prototype.getArr = function() { return this[arrKey]; }; return A; function A(a, b) { this.a = a; this.b = b; this[arrKey] = [a, b]; }; })(); var a1 = new A(1, 2); console.log(a1.getArr()); // [1, 2] 

      Well, if you really want to, and the conditional privacy of characters does not suit you, then you can (if you have WeakMap from ES6):

       var Smth = (function () { var privates = new WeakMap; function Smth(x, y) { this.x = x; privates.set(this, {y: y}); } Smth.prototype.doSmth = function () { console.log(this.x + ' ' + privates.get(this).y); }; return Smth; })(); var a = new Smth(10, 13); var b = new Smth(123, 167); a.doSmth(); b.doSmth(); 

        As one of the options, so:

         function A(a,b){ this.a = a; this.b = b; var arr = [a,b]; A.prototype.getArr = function () { return arr; } } A.prototype.A1 = function(){ console.log(this.a); }; A.prototype.A2 = function(){ console.log(A.prototype.getArr()); }; var a1 = new A(1,2); a1.A1();//1 a1.A2();//[1, 2] 

        Added:

        If with multiple instances, then you can try:

         function A(a, b) { this.a = a; this.b = b; var arr = [a, b]; this.xxx = arr; } A.prototype.A1 = function(){ console.log(this.a); }; A.prototype.A2 = function(){ console.log(this.xxx); }; var a1 = new A(1,2); var a2 = new A(2,3); var a3 = new A(3,4); a1.A1();//1 a1.A2();//[1, 2] a2.A2();//[2, 3] a3.A2();//[3, 4] 

        In general, if we assume that function A cannot be changed, then, apparently, the value of arr cannot be obtained.

        • one
          try to create several objects and see what output A2 - Grundy
        • Then this.getArr = function(){return arr.slice();} - vp_arth
        • .slice() in this particular case has no effect. - GHosT
        • .slice returns a copy, implementing read-only access. If rw access is needed, there is no reason not to write this.arr=[this.a, this.b] - vp_arth

        You can use the "getter" and get the value like this:

         function A(a,b){ this.a = a; this.b = b; var arr = [a,b]; this.getArray = function () { return arr; } } A.prototype.A1 = function(){ console.log(this.a); } A.prototype.A2 = function(){ console.log(this.getArray()); } var a1 = new A(1,2); a1.A1(); a1.A2(); 

        • one
          And where do you getter here? - vp_arth
        • @vp_arth This is me figuratively speaking. It is as abstract as private properties via underscore - David Arutiunian

        All variables declared inside the function are private to it. They can be accessed only from the function itself and through the closure of the nested ones.

        Since in the normal implementation of a class, functions are placed in the prototype and exist in a single copy, they cannot gain access to instance variables through a closure (there is one function, but there are many instances — the function cannot “choose” the closure at the time of the call).

        The following solutions are possible:

        Classic underscore in name

        If the name begins with an underscore, then by oral agreement it is considered that it should not be touched. Naturally, at the code level, this does not provide any privacy.

        Discard methods in prototype and place methods in instances

        Privacy is thus ensured, however, a large number of functions of the same type are created, differing only in closures.

        This approach is considered to be irrational, but it is quite common in the implementation of various services, which are essentially singletones.

        Use Symbol as Key

        The Symbol type is a special type of key. You can access the field value only by having the character itself, through which this value was recorded.

        This is quite similar to privacy, but does not provide full protection against access, since all the character keys for an object can be obtained through Object.getOwnPropertySymbols .

        Symbol is ES6. Polyphiles for it generate a regular field with a sufficiently random key to eliminate intersections with other fields.

        Use a dictionary in the closure

        A single closure may be common to the constructor and all prototype methods. But instances should be somehow distinguished. If we put into this closure something where the instance is the key, and the value is the entire set of private fields, then we get complete real privacy.

        However, there is a problem. If we keep something like an array, it will keep all our objects from garbage collection, that is, we get a memory leak. This problem is solved by the WeakMap introduced in ES6, which allows the garbage collector to destroy objects that are its keys.

        Polyphil for WeakMap is to put a certain field in the object itself and save the name of this field in the map. In fact, we slide to the previous method.

          Here I wrote it all and I realized that privacy is still not quite real. You can replace the private function (you could solve it with readonly in defineProperty, but you can still Object.create on top and the protection does not work) and get the key that is given to it, and then extract the data using this key.

          Still, I thought of a way to get full privacy in ES5:

          But still interesting. Maybe someone thinks of this idea to the end.

           var Smth = (function () { var PKEY = {}; // Объект-ключ для доступа к приватным данным, который // доступен только в замыкании, т. к. нигде не отдаётся наружу function Smth(x, y) { this.x = x; var privates = {y:y}; // Объект с приватными значениями, который // отдаётся только через функцию this.private // ... которая его не отдаст, если ей не дадут ключ var me = this; this.private = function (pkey) { if (this && this !== window && this !== me) { throw new Error("Do not call `private` on foreign object"); } if (pkey === PKEY) { return privates; // PKEY снаружи не знают, значит обращение идёт изнутри } throw new Error("Access to privates is denied"); } } Smth.prototype.doSmth = function () { var privates = this.private(PKEY); console.log(this.x + ' ' + privates.y); }; return Smth; })(); var a = new Smth(10, 13); var b = new Smth(123, 167); a.doSmth(); b.doSmth(); 

          But this method still needs to be adapted for inheritance, since each successor overwrites the parent implementation of this.private , it turns out that the parent class does not lose its private object. To prevent this from happening, you need to slightly change the implementation of the method so that it passes the call to the parent method (after all, it will also check its own key). And leave the exception to the last level, when the parent method is no longer there.

          The following code only Smth function in Smth

           var Smth = (function () { var PKEY = {}; // Объект-ключ для доступа к приватным данным, который // доступен только в замыкании, т. к. нигде не отдаётся наружу function Smth(x, y) { var basePrivate = this.private; // Тут получится undefined this.x = x; var privates = {y:y}; // Объект с приватными значениями, который // отдаётся только через функцию this.private // ... которая его не отдаст, если ей не дадут ключ var me = this; this.private = function (pkey) { if (this && this !== window && this !== me) { throw new Error("Do not call `private` to foreign object"); } if (pkey === PKEY) { return privates; // PKEY снаружи не знают, значит обращение идёт изнутри } if (basePrivate) { return basePrivate(pkey); } throw new Error("Access to privates is denied"); } } Smth.prototype.doSmth = function () { var privates = this.private(PKEY); console.log(this.x + ' ' + privates.y); }; return Smth; })(); var Derived = (function () { var PKEY = {}; // Объект-ключ для доступа к приватным данным, который // доступен только в замыкании, т. к. нигде не отдаётся наружу function Derived(x, y, a, b) { Smth.call(this, x, y); var basePrivate = this.private; // Это функция - она не вызывается тут this.a = a; var privates = {b:b}; // Объект с приватными значениями, который // отдаётся только через функцию this.private // ... которая его не отдаст, если ей не дадут ключ var me = this; this.private = function (pkey) { if (this && this !== window && this !== me) { throw new Error("Do not call `private` to foreign object"); } if (pkey === PKEY) { return privates; // PKEY снаружи не знают, значит обращение идёт изнутри } if (basePrivate) { return basePrivate(pkey); } throw new Error("Access to privates is denied"); } } Derived.prototype = Object.create(Smth.prototype); Derived.prototype.doOtherThing = function () { var privates = this.private(PKEY); console.log(this.x + ' ' + this.a + ' ' + privates.b); }; return Derived; })(); var a = new Derived(10, 13, -8, -67); var b = new Derived(123, 167, -411, -77); a.doSmth(); a.doOtherThing(); b.doSmth(); b.doOtherThing(); 

            arr declared only in function A To "embed" arr into a prototype, you need to write:

             function A(a,b){ this.a = a; this.b = b; this.arr = [a,b]; } 
            • And where is the encapsulation? - Qwertiy
            • You would not otherwise "embed" arr into the prototype - Vlad Gavriuk