Méthodes privées JavaScript

pour faire une classe JavaScript avec une méthode publique je ferais quelque chose comme:

function Restaurant() {}

Restaurant.prototype.buy_food = function(){
   // something here
}

Restaurant.prototype.use_restroom = function(){
   // something here
}

de Cette façon, les utilisateurs de ma classe:

var restaurant = new Restaurant();
restaurant.buy_food();
restaurant.use_restroom();

comment créer une méthode privée qui peut être appelée par les méthodes buy_food et use_restroom mais pas extérieurement par les utilisateurs de la classe?

en d'autres termes, je veux que ma méthode de mise en œuvre soit capable de faire:

Restaurant.prototype.use_restroom = function() {
   this.private_stuff();
}

mais cela ne devrait pas lieu de travail:

var r = new Restaurant();
r.private_stuff();

Comment puis-je définir private_stuff comme une méthode privée de ces vrai?

j'ai lu Doug Crockford de l'article intitulée quelques fois, mais il ne semble pas comme "privé" méthodes peuvent être appelées par des méthodes publiques et les "privilégiés" méthodes peuvent être appelées de l'extérieur.

406
demandé sur John Slegers 2008-09-11 05:12:39

29 réponses

vous pouvez le faire, mais l'inconvénient est qu'il ne peut pas faire partie du prototype:

function Restaurant()
{
    var myPrivateVar;

    var private_stuff = function()   // Only visible inside Restaurant()
    {
        myPrivateVar = "I can set this here!";
    }

    this.use_restroom = function()   // use_restroom is visible to all
    {
        private_stuff();
    }

    this.buy_food = function()    // buy_food is visible to all
    {
        private_stuff();
    }
}
343
répondu 17 of 26 2008-09-11 01:55:59

vous pouvez simuler des méthodes privées comme celle-ci:

function Restaurant() {
}

Restaurant.prototype = (function() {
    var private_stuff = function() {
        // Private code here
    };

    return {

        constructor:Restaurant,

        use_restroom:function() {
            private_stuff();
        }

    };
})();

var r = new Restaurant();

// This will work:
r.use_restroom();

// This will cause an error:
r.private_stuff();

plus d'informations sur cette technique ici: http://webreflection.blogspot.com/2008/04/natural-javascript-private-methods.html

154
répondu georgebrock 2012-02-06 22:31:06

à l'Aide de l'auto invocation de la fonction et de l'appeler

JavaScript utilise prototypes et n'a pas de classes (ou de méthodes) comme les langages orientés objet. Un développeur JavaScript doit penser en JavaScript.

Wikipedia citation:

contrairement à de nombreux langages orientés objet, il n'y a pas de distinction entre une définition de fonction et une définition de méthode. Plutôt, l' distinction se produit pendant l'appel de fonction; quand une fonction est appelée comme méthode d'un objet, la fonction locale de ce mot-clé est lié à celui l'objet de cette invocation.

Solution utilisant une fonction d'auto-invocation et la fonction d'appel pour appeler la "méthode" privée:

var MyObject = (function () {

    // Constructor
    function MyObject (foo) {
        this._foo = foo;
    }

    function privateFun (prefix) {
        return prefix + this._foo;
    }

    MyObject.prototype.publicFun = function () {
        return privateFun.call(this, '>>');
    }

    return MyObject;
})();


var myObject = new MyObject('bar');
myObject.publicFun();      // Returns '>>bar'
myObject.privateFun('>>'); // ReferenceError: private is not defined

la fonction d'appel permet d'appeler le privé fonction avec le contexte approprié ( this ).



plus simple avec noeud.js

si vous utilisez noeud.js , vous n'avez pas besoin du IIFE parce que vous pouvez profiter du module de chargement système :

function MyObject (foo) {
    this._foo = foo;
}

function privateFun (prefix) {
    return prefix + this._foo;
}

MyObject.prototype.publicFun = function () {
    return privateFun.call(this, '>>');
}

exports.MyObject = MyObject;

Charger le fichier:

var MyObject = require('./MyObject').MyObject;

var myObject = new MyObject('bar');
myObject.publicFun();      // Returns '>>bar'
myObject.privateFun('>>'); // ReferenceError: private is not defined



(expérimental) ES7 avec L'opérateur Bind

La liaison de l'opérateur :: est un ECMAScript proposition et est mis en place dans Babel ( stade 0 ).

export default class MyObject {
  constructor (foo) {
    this._foo = foo;
  }

  publicFun () {
    return this::privateFun('>>');
  }
}

function privateFun (prefix) {
  return prefix + this._foo;
}

Charger le fichier:

import MyObject from './MyObject';

let myObject = new MyObject('bar');
myObject.publicFun();      // Returns '>>bar'
myObject.privateFun('>>'); // TypeError: myObject.privateFun is not a function
132
répondu Yves M. 2016-09-24 14:50:55

dans ces situations où vous avez une API publique, et que vous souhaitez des méthodes/propriétés privées et publiques, j'utilise toujours le modèle de Module. Ce modèle a été rendu populaire dans la bibliothèque de YUI, et les détails peuvent être trouvés ici:

http://yuiblog.com/blog/2007/06/12/module-pattern /

c'est vraiment simple, et facile à comprendre pour les autres développeurs. Pour un exemple simple:

var MYLIB = function() {  
    var aPrivateProperty = true;
    var aPrivateMethod = function() {
        // some code here...
    };
    return {
        aPublicMethod : function() {
            aPrivateMethod(); // okay
            // some code here...
        },
        aPublicProperty : true
    };  
}();

MYLIB.aPrivateMethod() // not okay
MYLIB.aPublicMethod() // okay
32
répondu 2008-09-11 02:30:32

Voici la classe que J'ai créée pour comprendre ce que Douglas Crockford a suggéré dans son site membres privés en JavaScript

function Employee(id, name) { //Constructor
    //Public member variables
    this.id = id;
    this.name = name;
    //Private member variables
    var fName;
    var lName;
    var that = this;
    //By convention, we create a private variable 'that'. This is used to     
    //make the object available to the private methods. 

    //Private function
    function setFName(pfname) {
        fName = pfname;
        alert('setFName called');
    }
    //Privileged function
    this.setLName = function (plName, pfname) {
        lName = plName;  //Has access to private variables
        setFName(pfname); //Has access to private function
        alert('setLName called ' + this.id); //Has access to member variables
    }
    //Another privileged member has access to both member variables and private variables
    //Note access of this.dataOfBirth created by public member setDateOfBirth
    this.toString = function () {
        return 'toString called ' + this.id + ' ' + this.name + ' ' + fName + ' ' + lName + ' ' + this.dataOfBirth; 
    }
}
//Public function has access to member variable and can create on too but does not have access to private variable
Employee.prototype.setDateOfBirth = function (dob) {
    alert('setDateOfBirth called ' + this.id);
    this.dataOfBirth = dob;   //Creates new public member note this is accessed by toString
    //alert(fName); //Does not have access to private member
}
$(document).ready()
{
    var employee = new Employee(5, 'Shyam'); //Create a new object and initialize it with constructor
    employee.setLName('Bhaskar', 'Ram');  //Call privileged function
    employee.setDateOfBirth('1/1/2000');  //Call public function
    employee.id = 9;                     //Set up member value
    //employee.setFName('Ram');  //can not call Private Privileged method
    alert(employee.toString());  //See the changed object

}
19
répondu Sarath 2012-10-05 14:20:14

J'ai évoqué ceci: EDIT: en fait, quelqu'un a lié à une solution identique. Duh!

var Car = function() {
}

Car.prototype = (function() {
    var hotWire = function() {
        // Private code *with* access to public properties through 'this'
        alert( this.drive() ); // Alerts 'Vroom!'
    }

    return {
        steal: function() {
            hotWire.call( this ); // Call a private method
        },
        drive: function() {
            return 'Vroom!';
        }
    };
})();

var getAwayVechile = new Car();

hotWire(); // Not allowed
getAwayVechile.hotWire(); // Not allowed
getAwayVechile.steal(); // Alerts 'Vroom!'
13
répondu 2009-09-01 10:22:34

je pense que de telles questions reviennent encore et encore à cause du manque de compréhension des fermetures. La fermeture est la chose la plus importante dans JS. Chaque programmeur JS doit en ressentir l'essence.

1. tout d'abord, nous devons établir un champ d'application distinct (fermeture).

function () {

}

2. Dans ce domaine, nous pouvons faire ce que nous voulons. Et personne ne va le savoir.

function () {
    var name,
        secretSkills = {
            pizza: function () { return new Pizza() },
            sushi: function () { return new Sushi() }
        }

    function Restaurant(_name) {
        name = _name
    }
    Restaurant.prototype.getFood = function (name) {
        return name in secretSkills ? secretSkills[name]() : null
    }
}

3. pour que le monde sache à propos de notre classe de restaurant, on doit le rendre après la fermeture.

var Restaurant = (function () {
    // Restaurant definition
    return Restaurant
})()

4. à la fin, nous avons:

var Restaurant = (function () {
    var name,
        secretSkills = {
            pizza: function () { return new Pizza() },
            sushi: function () { return new Sushi() }
        }

    function Restaurant(_name) {
        name = _name
    }
    Restaurant.prototype.getFood = function (name) {
        return name in secretSkills ? secretSkills[name]() : null
    }
    return Restaurant
})()

5. aussi, cette approche a un potentiel d'héritage et de Templier

// Abstract class
function AbstractRestaurant(skills) {
    var name
    function Restaurant(_name) {
        name = _name
    }
    Restaurant.prototype.getFood = function (name) {
        return skills && name in skills ? skills[name]() : null
    }
    return Restaurant
}

// Concrete classes
SushiRestaurant = AbstractRestaurant({ 
    sushi: function() { return new Sushi() } 
})

PizzaRestaurant = AbstractRestaurant({ 
    pizza: function() { return new Pizza() } 
})

var r1 = new SushiRestaurant('Yo! Sushi'),
    r2 = new PizzaRestaurant('Dominos Pizza')

r1.getFood('sushi')
r2.getFood('pizza')

j'espère que cela aidera quelqu'un à mieux comprendre ce sujet

10
répondu imos 2013-08-14 03:06:00

toute cette fermeture vous coûtera. Assurez-vous de tester les implications de la vitesse en particulier dans IE. Vous trouverez, vous êtes mieux avec une convention de nommage. Il y a encore beaucoup d'utilisateurs du web d'entreprise là-bas qui sont forcés d'utiliser IE6...

8
répondu Kelly 2008-09-15 13:47:18

personnellement, je préfère le modèle suivant pour créer des classes en JavaScript:

var myClass = (function() {
    // Private class properties go here

    var blueprint = function() {
        // Private instance properties go here
        ...
    };

    blueprint.prototype = { 
        // Public class properties go here
        ...
    };

    return  {
         // Public class properties go here
        create : function() { return new blueprint(); }
        ...
    };
})();

Comme vous pouvez le voir, il vous permet de définir des propriétés de classe et d'instance propriétés, qui peuvent être publics ou privés.


Démo

var Restaurant = function() {
    var totalfoodcount = 0;        // Private class property
    var totalrestroomcount  = 0;   // Private class property
    
    var Restaurant = function(name){
        var foodcount = 0;         // Private instance property
        var restroomcount  = 0;    // Private instance property
        
        this.name = name
        
        this.incrementFoodCount = function() {
            foodcount++;
            totalfoodcount++;
            this.printStatus();
        };
        this.incrementRestroomCount = function() {
            restroomcount++;
            totalrestroomcount++;
            this.printStatus();
        };
        this.getRestroomCount = function() {
            return restroomcount;
        },
        this.getFoodCount = function() {
            return foodcount;
        }
    };
   
    Restaurant.prototype = {
        name : '',
        buy_food : function(){
           this.incrementFoodCount();
        },
        use_restroom : function(){
           this.incrementRestroomCount();
        },
        getTotalRestroomCount : function() {
            return totalrestroomcount;
        },
        getTotalFoodCount : function() {
            return totalfoodcount;
        },
        printStatus : function() {
           document.body.innerHTML
               += '<h3>Buying food at '+this.name+'</h3>'
               + '<ul>' 
               + '<li>Restroom count at ' + this.name + ' : '+ this.getRestroomCount() + '</li>'
               + '<li>Food count at ' + this.name + ' : ' + this.getFoodCount() + '</li>'
               + '<li>Total restroom count : '+ this.getTotalRestroomCount() + '</li>'
               + '<li>Total food count : '+ this.getTotalFoodCount() + '</li>'
               + '</ul>';
        }
    };

    return  { // Singleton public properties
        create : function(name) {
            return new Restaurant(name);
        },
        printStatus : function() {
          document.body.innerHTML
              += '<hr />'
              + '<h3>Overview</h3>'
              + '<ul>' 
              + '<li>Total restroom count : '+ Restaurant.prototype.getTotalRestroomCount() + '</li>'
              + '<li>Total food count : '+ Restaurant.prototype.getTotalFoodCount() + '</li>'
              + '</ul>'
              + '<hr />';
        }
    };
}();

var Wendys = Restaurant.create("Wendy's");
var McDonalds = Restaurant.create("McDonald's");
var KFC = Restaurant.create("KFC");
var BurgerKing = Restaurant.create("Burger King");

Restaurant.printStatus();

Wendys.buy_food();
Wendys.use_restroom();
KFC.use_restroom();
KFC.use_restroom();
Wendys.use_restroom();
McDonalds.buy_food();
BurgerKing.buy_food();

Restaurant.printStatus();

BurgerKing.buy_food();
Wendys.use_restroom();
McDonalds.buy_food();
KFC.buy_food();
Wendys.buy_food();
BurgerKing.buy_food();
McDonalds.buy_food();

Restaurant.printStatus();

Voir aussi ce violon .

6
répondu John Slegers 2017-06-07 22:02:10

prendre l'une des solutions qui suivent Crockford's privé ou privilégié modèle. Par exemple:

function Foo(x) {
    var y = 5;
    var bar = function() {
        return y * x;
    };

    this.public = function(z) {
        return bar() + x * z;
    };
}

dans tous les cas où l'attaquant n'a pas de droit" d'exécution "sur le contexte JS, il n'a aucun moyen d'accéder à des champs OU méthodes" publics "ou" privés". Si l'attaquant dispose de cet accès, il peut exécuter ce liner:

eval("Foo = " + Foo.toString().replace(
    /{/, "{ this.eval = function(code) { return eval(code); }; "
));

notez que le code ci-dessus est générique à tous les constructeur de type-confidentialité. Il échouera avec certaines des solutions ici, mais il devrait être clair que presque toutes les solutions basées sur la fermeture peuvent être cassées comme ceci avec différents paramètres replace() .

après cette exécution tout objet créé avec new Foo() va avoir une méthode eval qui peut être appelée pour retourner ou changer des valeurs ou des méthodes définies dans la fermeture du constructeur, par exemple:

f = new Foo(99);
f.eval("x");
f.eval("y");
f.eval("x = 8");

le seul problème que je vois avec ça, c'est que ça ne marchera pas pour les cas où il n'y a qu'une seule instance et qu'elle est créée en charge. Mais alors il n'y a aucune raison de définir réellement un prototype et dans ce cas l'attaquant peut simplement recréer l'objet au lieu du constructeur aussi longtemps qu'il a une façon de passer les mêmes paramètres (par exemple ils sont constants ou calculés à partir des valeurs disponibles).

à mon avis, Cela fait à peu près solution inutile. étant donné que la" vie privée "est facilement décomposée les inconvénients de sa solution (lisibilité et maintenabilité réduites, performances réduites, mémoire accrue) rend la méthode basée sur le prototype" no privacy " le meilleur choix.

j'utilise habituellement des underscores menant à marquer __private et _protected méthodes et champs (style Perl), mais l'idée d'avoir la vie privée en JavaScript montre juste comment c'est un langage mal compris.

par conséquent, je ne suis pas d'accord avec Crockford sauf pour sa première phrase.

alors comment obtenir une vraie vie privée à JS? mettez tout ce qui est nécessaire pour être privé du côté du serveur et utilisez JS pour faire des appels AJAX.

3
répondu Fozi 2014-08-18 16:50:28

l'apothéose du motif du Module: le motif du Module révélateur

une jolie petite extension à un motif très robuste.

2
répondu Daniel Stockman 2008-09-11 03:10:32

si vous voulez la gamme complète de fonctions publiques et privées avec la possibilité pour les fonctions publiques d'accéder à des fonctions privées, le code de disposition pour un objet comme celui-ci:

function MyObject(arg1, arg2, ...) {
  //constructor code using constructor arguments...
  //create/access public variables as 
  // this.var1 = foo;

  //private variables

  var v1;
  var v2;

  //private functions
  function privateOne() {
  }

  function privateTwon() {
  }

  //public functions

  MyObject.prototype.publicOne = function () {
  };

  MyObject.prototype.publicTwo = function () {
  };
}
2
répondu domgblackwell 2008-09-29 10:39:21

et ça?

var Restaurant = (function() {

 var _id = 0;
 var privateVars = [];

 function Restaurant(name) {
     this.id = ++_id;
     this.name = name;
     privateVars[this.id] = {
         cooked: []
     };
 }

 Restaurant.prototype.cook = function (food) {
     privateVars[this.id].cooked.push(food);
 }

 return Restaurant;

})();

recherche de variables privées est impossible en dehors de la portée de la fonction immédiate. Il n'y a pas de chevauchement de fonctions, d'économiser la mémoire.

l'inconvénient est que la recherche de variables privées est clunky privateVars[this.id].cooked est ridicule à taper. Il y a aussi une variable "id" supplémentaire.

2
répondu Evan Leis 2015-02-18 13:43:29
var TestClass = function( ) {

    var privateProperty = 42;

    function privateMethod( ) {
        alert( "privateMethod, " + privateProperty );
    }

    this.public = {
        constructor: TestClass,

        publicProperty: 88,
        publicMethod: function( ) {
            alert( "publicMethod" );
            privateMethod( );
        }
    };
};
TestClass.prototype = new TestClass( ).public;


var myTestClass = new TestClass( );

alert( myTestClass.publicProperty );
myTestClass.publicMethod( );

alert( myTestClass.privateMethod || "no privateMethod" );

similaire à georgebrock mais un peu moins verbeux (IMHO) Aucun problème avec cette façon de faire? (Je n'ai pas vu nulle part)

edit: j'ai réalisé que c'était un peu inutile puisque chaque instance indépendante a sa propre copie des méthodes publiques, minant ainsi l'utilisation du prototype.

1
répondu David 2011-05-23 07:32:39

le motif du module est correct dans la plupart des cas. Mais si vous avez des milliers d'instances, les classes sauvegardent la mémoire. Si sauver de la mémoire est un problème et vos objets contiennent une petite quantité de données privées, mais ont beaucoup de fonctions publiques, alors vous voudrez toutes les fonctions publiques à vivre dans le .prototype pour sauver la mémoire.

C'est ce que j'ai trouvé:

var MyClass = (function () {
    var secret = {}; // You can only getPriv() if you know this
    function MyClass() {
        var that = this, priv = {
            foo: 0 // ... and other private values
        };
        that.getPriv = function (proof) {
            return (proof === secret) && priv;
        };
    }
    MyClass.prototype.inc = function () {
        var priv = this.getPriv(secret);
        priv.foo += 1;
        return priv.foo;
    };
    return MyClass;
}());
var x = new MyClass();
x.inc(); // 1
x.inc(); // 2

L'objet priv contient des propriétés privées. Il est accessible par le biais de la fonction publique getPriv() , mais cette fonction renvoie false à moins que vous ne passiez la secret , et ceci est seulement connu à l'intérieur de la fermeture principale.

1
répondu James 2015-02-02 14:28:19

envelopper tout le code dans la fonction anonyme: alors, toutes les fonctions seront privées ,seulement les fonctions attachées à window objet:

(function(w,nameSpacePrivate){
     w.Person=function(name){
         this.name=name;   
         return this;
     };

     w.Person.prototype.profilePublic=function(){
          return nameSpacePrivate.profile.call(this);
     };  

     nameSpacePrivate.profile=function(){
       return 'My name is '+this.name;
     };

})(window,{});

utilisez ceci:

  var abdennour=new Person('Abdennour');
  abdennour.profilePublic();

VIOLON

1
répondu Abdennour TOUMI 2015-06-25 05:48:30

les fonctions privées ne peuvent pas accéder aux variables publiques en utilisant le modèle de module

0
répondu Dooma 2011-05-29 19:37:04

depuis que tout le monde a posté son propre code, je vais le faire aussi...

J'aime bien Crockford parce qu'il a introduit des motifs réels orientés objet en Javascript. Mais il est aussi venu avec un nouveau malentendu, le "qui".

alors pourquoi utilise-t-il"ça = ça"? Il n'a rien à voir avec les fonctions privées. Il a à voir avec les fonctions internes!

parce que D'après Crockford c'est un code buggy:

Function Foo( ) {
    this.bar = 0; 
    var foobar=function( ) {
        alert(this.bar);
    }
} 

donc il a suggéré de faire ceci:

Function Foo( ) {
    this.bar = 0;
    that = this; 
    var foobar=function( ) {
        alert(that.bar);
    }
}

donc comme je l'ai dit, Je suis tout à fait sûr que Crockford avait tort son explication à ce sujet et ceci (mais son code est certainement correct). Ou était-il en train de tromper le monde Javascript, pour savoir qui copie son code? Je ne sais pas...Je ne suis pas un geek de navigateur ;d

MODIFIER

Ah, c'est ça le problème: What does ' var que = ce;' signifie en JavaScript?

donc Crockie avait vraiment tort avec son explication....mais juste avec son code, donc c'est toujours un type bien. :))

0
répondu mark 2017-05-23 11:54:41

En général, j'ai ajouté de l'Objet privé _ temporairement à l'objet. Vous devez ouvrir la confidentialité exlipcitly dans le "constructeur" de la méthode. Si vous appelez la méthode du prototype, vous pouvoir écraser le prototype-méthode

  • Rendre publique une méthode accessible dans le "constructeur": (ctx est le contexte de l'objet)

    ctx.test = GD.Fabric.open('test', GD.Test.prototype, ctx, _); // is a private object
    
  • maintenant j'ai cette openPrivacy:

    GD.Fabric.openPrivacy = function(func, clss, ctx, _) {
        return function() {
            ctx._ = _;
            var res = clss[func].apply(ctx, arguments);
            ctx._ = null;
            return res;
        };
    };
    
0
répondu Andreas Dyballa 2013-04-20 22:03:20

C'est ce que j'ai calculé:

nécessite une classe de code de sucre que vous pouvez trouver ici . Prend aussi en charge les objets protégés, hérités, virtuels, statiques...

;( function class_Restaurant( namespace )
{
    'use strict';

    if( namespace[ "Restaurant" ] ) return    // protect against double inclusions

        namespace.Restaurant = Restaurant
    var Static               = TidBits.OoJs.setupClass( namespace, "Restaurant" )


    // constructor
    //
    function Restaurant()
    {
        this.toilets = 3

        this.Private( private_stuff )

        return this.Public( buy_food, use_restroom )
    }

    function private_stuff(){ console.log( "There are", this.toilets, "toilets available") }

    function buy_food     (){ return "food"        }
    function use_restroom (){ this.private_stuff() }

})( window )


var chinese = new Restaurant

console.log( chinese.buy_food()      );  // output: food
console.log( chinese.use_restroom()  );  // output: There are 3 toilets available
console.log( chinese.toilets         );  // output: undefined
console.log( chinese.private_stuff() );  // output: undefined

// and throws: TypeError: Object #<Restaurant> has no method 'private_stuff'
0
répondu 2013-08-14 19:10:18
Class({  
    Namespace:ABC,  
    Name:"ClassL2",  
    Bases:[ABC.ClassTop],  
    Private:{  
        m_var:2  
    },  
    Protected:{  
        proval:2,  
        fight:Property(function(){  
            this.m_var--;  
            console.log("ClassL2::fight (m_var)" +this.m_var);  
        },[Property.Type.Virtual])  
    },  
    Public:{  
        Fight:function(){  
            console.log("ClassL2::Fight (m_var)"+this.m_var);  
            this.fight();  
        }  
    }  
});  

https://github.com/nooning/JSClass

0
répondu snowkid 2013-12-10 17:27:20

j'ai créé un nouvel outil pour vous permettre d'avoir de vraies méthodes privées sur le prototype https://github.com/TremayneChrist/ProtectJS

exemple:

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
0
répondu Trem 2014-05-29 14:57:51

vous devez mettre une fermeture autour de votre constructeur-fonction réelle, où vous pouvez définir vos méthodes privées. Pour changer les données des instances à travers ces méthodes privées, vous devez leur donner "ceci" avec elles, soit comme argument de fonction, soit en appelant cette fonction avec .appliquer(ce) :

var Restaurant = (function(){
    var private_buy_food = function(that){
        that.data.soldFood = true;
    }
    var private_take_a_shit = function(){
        this.data.isdirty = true;   
    }
    // New Closure
    function restaurant()
    {
        this.data = {
            isdirty : false,
            soldFood: false,
        };
    }

    restaurant.prototype.buy_food = function()
    {
       private_buy_food(this);
    }
    restaurant.prototype.use_restroom = function()
    {
       private_take_a_shit.call(this);
    }
    return restaurant;
})()

// TEST:

var McDonalds = new Restaurant();
McDonalds.buy_food();
McDonalds.use_restroom();
console.log(McDonalds);
console.log(McDonalds.__proto__);
0
répondu Flex Elektro Deimling 2014-08-09 14:39:08

voici ce que j'ai le plus apprécié jusqu'à présent en ce qui concerne les méthodes/membres privés/publics et instanciation en javascript:

voici l'article: http://www.sefol.com/?p=1090

et voici l'exemple:

var Person = (function () {

    //Immediately returns an anonymous function which builds our modules 
    return function (name, location) {

        alert("createPerson called with " + name);

        var localPrivateVar = name;

        var localPublicVar = "A public variable";

        var localPublicFunction = function () {
            alert("PUBLIC Func called, private var is :" + localPrivateVar)
        };

        var localPrivateFunction = function () {
            alert("PRIVATE Func called ")
        };

        var setName = function (name) {

            localPrivateVar = name;

        }

        return {

            publicVar: localPublicVar,

            location: location,

            publicFunction: localPublicFunction,

            setName: setName

        }

    }
})();


//Request a Person instance - should print "createPerson called with ben"
var x = Person("ben", "germany");

//Request a Person instance - should print "createPerson called with candide"
var y = Person("candide", "belgium");

//Prints "ben"
x.publicFunction();

//Prints "candide"
y.publicFunction();

//Now call a public function which sets the value of a private variable in the x instance
x.setName("Ben 2");

//Shouldn't have changed this : prints "candide"
y.publicFunction();

//Should have changed this : prints "Ben 2"
x.publicFunction();

JSFiddle: http://jsfiddle.net/northkildonan/kopj3dt3/1 /

0
répondu low_rents 2014-12-10 09:01:44

je sais que c'est un peu tard, mais qu'en est-il?

var obj = function(){
    var pr = "private";
    var prt = Object.getPrototypeOf(this);
    if(!prt.hasOwnProperty("showPrivate")){
        prt.showPrivate = function(){
            console.log(pr);
        }
    }    
}

var i = new obj();
i.showPrivate();
console.log(i.hasOwnProperty("pr"));
0
répondu Maxim Balaganskiy 2015-01-28 11:36:38

il y a déjà beaucoup de réponses à cette question, mais rien ne correspondait à mes besoins. Alors j'ai trouvé ma propre solution, j'espère qu'elle est utile pour quelqu'un:

function calledPrivate(){
    var stack = new Error().stack.toString().split("\n");
    function getClass(line){
        var i = line.indexOf(" ");
        var i2 = line.indexOf(".");
        return line.substring(i,i2);
    }
    return getClass(stack[2])==getClass(stack[3]);
}

class Obj{
    privateMethode(){
        if(calledPrivate()){
            console.log("your code goes here");
        }
    }
    publicMethode(){
        this.privateMethode();
    }
}

var obj = new Obj();
obj.publicMethode(); //logs "your code goes here"
obj.privateMethode(); //does nothing

comme vous pouvez le voir ce système fonctionne lorsque vous utilisez ce type de classes en javascript. Aussi loin que j'ai compris aucune des méthodes commentées ci-dessus n'.

0
répondu thegunmaster 2016-05-10 18:49:19

Voir cette réponse pour un clean & simple "classe" de la solution avec un public et privé de l'interface et de support pour la composition

0
répondu kofifus 2017-09-23 02:08:27

je préfère stocker des données privées dans un WeakMap . Cela vous permet de garder vos méthodes publiques sur le prototype à laquelle ils appartiennent. Cela semble être la façon la plus efficace de gérer ce problème pour un grand nombre d'objets.

const data = new WeakMap();

function Foo(value) {
    data.set(this, {value});
}

// public method accessing private value
Foo.prototype.accessValue = function() {
    return data.get(this).value;
}

// private 'method' accessing private value
function accessValue(foo) {
    return data.get(foo).value;
}

export {Foo};
0
répondu rich remer 2018-02-16 19:55:30

ne sois pas si bavard. C'est Javascript. Utiliser une Convention D'appellation .

après des années de travail dans les classes es6, j'ai récemment commencé à travailler sur un projet es5 (en utilisant des requireJS qui est déjà très verbeux). J'ai passé en revue toutes les stratégies mentionnées ici et tout se résume essentiellement à utiliser une convention de nommage :

  1. Javascript n'a pas de mots-clés scope comme private . Les autres développeurs qui entrent Javascript le savent déjà. Par conséquent, une simple convention d'appellation est plus que suffisante. Une simple convention de nommage du préfixe avec un underscore résout le problème des propriétés privées et des méthodes privées.
  2. profitons du Prototype pour des raisons de vitesse, mais ne faisons pas plus verbeux que cela. Essayons de garder la "classe" es5 à la recherche de ce que nous pourrions attendre dans d'autres langues d'arrière-plan (et traiter chaque fichier en tant que classe, même si nous n'avons pas besoin de retourner une instance).
  3. faisons une démonstration avec une situation de module plus réaliste (nous utiliserons les anciennes exigences es5 et old requireJs).

mon-info-bulle.js

    define([
        'tooltip'
    ],
    function(
        tooltip
    ){

        function MyTooltip() {
            // Later, if needed, we can remove the underscore on some
            // of these (make public) and allow clients of our class
            // to set them.
            this._selector = "#my-tooltip"
            this._template = 'Hello from inside my tooltip!';
            this._initTooltip();
        }

        MyTooltip.prototype = {
            constructor: MyTooltip,

            _initTooltip: function () {
                new tooltip.tooltip(this._selector, {
                    content: this._template,
                    closeOnClick: true,
                    closeButton: true
                });
            }
        }

        return {
            init: function init() {
               new MyTooltip();  // <-- Our constructor adds our tooltip to the DOM so not much we need to do after instantiation.
            }

            // You could instead return a new instantiation, 
            // if later you do more with this class.
            /* 
            create: function create() {
               return new MyTooltip();
            }
            */
        }
    });
0
répondu prograhammer 2018-07-22 23:32:41