JavaScript métodos privados


Para hacer una clase JavaScript con un método público haría algo como:

function Restaurant() {}

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

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

De esa manera los usuarios de mi clase pueden:

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

¿Cómo puedo crear un método privado que puede ser llamado por los métodos buy_food y use_restroom pero no externamente por los usuarios de la clase?

En otras palabras, quiero que mi implementación del método sea capaz de hacer:

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

Pero esto no debería funcionar:

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

¿Cómo defino private_stuff como un método privado para que ambos sean verdaderos?

He lea la valoración crítica de Doug Crockford algunas veces, pero no parece que los métodos "privados" puedan ser llamados por métodos públicos y los métodos "privilegiados" puedan ser llamados externamente.

Author: John Slegers, 2008-09-11

29 answers

Puedes hacerlo, pero la desventaja es que no puede ser parte del prototipo:

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
Author: 17 of 26,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-11 01:55:59

Puede simular métodos privados como este:

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();

Más información sobre esta técnica aquí: http://webreflection.blogspot.com/2008/04/natural-javascript-private-methods.html

 154
Author: georgebrock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-06 22:31:06

Usando la función de auto invocación y llamar a

JavaScript utiliza prototipos y no tiene clases (o métodos para el caso) como los lenguajes Orientados a objetos. Un desarrollador de JavaScript necesita pensar en JavaScript.

Cita de Wikipedia:

A diferencia de muchos lenguajes orientados a objetos, no hay distinción entre una definición de función y una definición de método. Más bien, la distinción ocurre durante la llamada a una función; cuando se llama a una función como método de un objeto, la función local de esta palabra clave está vinculada a objeto para esa invocación.

Solución usando una función de auto invocación y la función de llamada para llamar al "método" privado:

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

El call function nos permite llamar a la función privada con el contexto apropiado (this).


Más simple con Node.js

Si está utilizando el nodo .js , no necesitas la VIDA porque puedes aprovechar el sistema de carga de módulos :

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

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

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

exports.MyObject = MyObject;

Cargar el archivo:

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

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


(experimental) ES7 con el Operador Bind

El operador bind :: es una propuesta de ECMAScript y está implementado en Babel (fase 0 ).

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

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

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

Cargar el archivo:

import MyObject from './MyObject';

let myObject = new MyObject('bar');
myObject.publicFun();      // Returns '>>bar'
myObject.privateFun('>>'); // TypeError: myObject.privateFun is not a function
 132
Author: Yves M.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-24 14:50:55

En estas situaciones cuando tienes una API pública, y quieres métodos/propiedades privadas y públicas, siempre uso el Patrón de módulo. Este patrón se hizo popular dentro de la biblioteca YUI, y los detalles se pueden encontrar aquí:

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

Es realmente sencillo y fácil de comprender para otros desarrolladores. Para un ejemplo 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
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-11 02:30:32

Aquí está la clase que creé para entender lo que Douglas Crockford ha sugerido en su sitio Miembros privados 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
Author: Sarath,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-05 14:20:14

He conjurado esto: EDITAR: En realidad, alguien ha vinculado a una solución idéntica. 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
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-01 10:22:34

Creo que tales preguntas surgen una y otra vez debido a la falta de comprensión de los cierres. Cierres es lo más importante en JS. Cada programador de JS tiene que sentir la esencia de ello.

1. En primer lugar tenemos que hacer un alcance separado (cierre).

function () {

}

2. En esta área, podemos hacer lo que queramos. Y nadie lo sabrá.

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. Para que el mundo conozca nuestra clase de restaurante, tenemos que devolverlo de la cierre.

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

4. al final, tenemos:

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. Además, este enfoque tiene potencial para la herencia y la creación de plantillas

// 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')

Espero que esto ayude a alguien a entender mejor este tema

 10
Author: imos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-14 03:06:00

Todo este cierre te costará. Asegúrese de probar las implicaciones de velocidad especialmente en IE. Usted encontrará que está mejor con una convención de nomenclatura. Todavía hay una gran cantidad de usuarios web corporativos por ahí que se ven obligados a utilizar IE6...

 8
Author: Kelly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-15 13:47:18

Personalmente, prefiero el siguiente patrón para crear clases 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(); }
        ...
    };
})();

Como puede ver, le permite definir tanto propiedades de clase como propiedades de instancia, cada una de las cuales puede ser pública y privada.


Demo

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();

Ver también este Violín.

 6
Author: John Slegers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-07 22:02:10

Tome cualquiera de las soluciones que siguen el patrón de Crockford privateo priviledged. Por ejemplo:

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

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

En cualquier caso donde el atacante no tiene derecho a "ejecutar" en el contexto JS, no tiene forma de acceder a ningún campo o método "público" o "privado". En caso de que el atacante tenga ese acceso, puede ejecutar este one-liner:

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

Tenga en cuenta que el código anterior es genérico para todos los constructores-type-privacy. Fallará con algunas de las soluciones aquí, pero debe quedar claro que casi todas las soluciones basadas en cierres se pueden romper así con diferentes parámetros replace().

Después de que esto se ejecute, cualquier objeto creado con new Foo() tendrá un método eval al que se puede llamar para devolver o cambiar valores o métodos definidos en el cierre del constructor, por ejemplo:

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

El único problema que puedo ver con esto es que no funcionará para casos donde solo hay una instancia y se crea al cargar. Pero entonces no hay razón para definir realmente un prototipo y en ese caso el atacante puede simplemente recrear el objeto en lugar del constructor siempre y cuando tenga una forma de pasar los mismos parámetros (por ejemplo, son constantes o calculados a partir de valores disponibles).

En mi opinión, esto hace prácticamente inútil la solución de Crockford. Dado que la "privacidad" se rompe fácilmente, las desventajas de su solución (menor legibilidad y mantenibilidad, menor rendimiento, mayor memoria) hacen que el "no privacidad " prototype based method la mejor opción.

Normalmente uso guiones bajos para marcar __private y _protected métodos y campos (estilo Perl), pero la idea de tener privacidad en JavaScript solo muestra cómo es un lenguaje mal entendido.

Por lo tanto, no estoy de acuerdo con Crockford excepto por su primera frase.

Entonces, ¿cómo se obtiene privacidad real en JS? Ponga todo lo que se requiere para ser privado en el lado del servidor y use JS para hacer AJAX llama.

 3
Author: Fozi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-18 16:50:28

La apoteosis del Patrón del Módulo: El Patrón del Módulo Revelador

Una pequeña extensión ordenada a un patrón muy robusto.

 2
Author: Daniel Stockman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-11 03:10:32

Si desea la gama completa de funciones públicas y privadas con la capacidad de que las funciones públicas accedan a funciones privadas, diseñe el código para un objeto como este:

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
Author: domgblackwell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-29 10:39:21

¿Qué pasa con esto?

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;

})();

La búsqueda de variables privadas es imposible fuera del alcance de la función inmediata. No hay duplicación de funciones, ahorrando memoria.

El inconveniente es que la búsqueda de variables privadas es torpe privateVars[this.id].cooked es ridículo escribir. También hay una variable adicional" id".

 2
Author: Evan Leis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
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" );

Similar a georgebrock pero un poco menos detallado (IMHO) ¿Algún problema con hacerlo de esta manera? (No lo he visto en ninguna parte)

Editar: Me di cuenta de que esto es un poco inútil ya que cada instanciación independiente tiene su propia copia de los métodos públicos, socavando así el uso del prototipo.

 1
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-23 07:32:39

El patrón del módulo es correcto en la mayoría de los casos. Pero si tiene miles de instancias, las clases ahorran memoria. Si el ahorro de memoria es una preocupación y sus objetos contienen una pequeña cantidad de datos privados, pero tienen una gran cantidad de funciones públicas, entonces usted querrá que todas las funciones públicas para vivir en el .prototipo para ahorrar memoria.

Esto es lo que se me ocurrió:

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

El objeto priv contiene propiedades privadas. Es accesible a través de la función pública getPriv(), pero esta función devuelve false a menos que le pases el secret, y esto solo se conoce dentro del cierre principal.

 1
Author: James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-02 14:28:19

Envolver todo el código en Función Anónima: Entonces, todas las funciones serán privadas, SOLO las funciones adjuntas al objeto window:

(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,{});

Usa esto:

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

FIDDLE

 1
Author: Abdennour TOUMI,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-25 05:48:30

Las funciones privadas no pueden acceder a las variables públicas usando module pattern

 0
Author: Dooma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-29 19:37:04

Ya que todo el mundo estaba publicando aquí su propio código, voy a hacer eso también...

Me gusta Crockford porque introdujo patrones orientados a objetos reales en Javascript. Pero también se le ocurrió un nuevo malentendido, el "ese".

Entonces, ¿por qué está usando "eso = esto"? No tiene nada que ver con funciones privadas en absoluto. ¡Tiene que ver con las funciones internas!

Porque según Crockford este es un código con errores:

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

Así que sugirió hacer esto:

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

Así que como dije, estoy bastante seguro de que Crockford estaba equivocado en su explicación sobre eso y esto (pero su código es ciertamente correcto). ¿O solo estaba engañando al mundo Javascript, para saber quién está copiando su código? No sé...No soy un geek del navegador; D

EDITAR

Ah, de eso se trata: ¿Qué significa 'var that = this;' en JavaScript?

Así que Crockie estaba realmente equivocado con su explicación....pero justo con su código, así que sigue siendo un gran tipo. :))

 0
Author: mark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:41

En general agregué el Objeto privado _ temporalmente al objeto. Usted tiene que abrir la privacidad exlipcitly en el" Power-constructor " para el método. Si llama al método desde el prototipo, lo hará ser capaz de sobrescribir el método prototipo

  • Hacer accesible un método público en el "Power-constructor": (ctx es el contexto del objeto)

    ctx.test = GD.Fabric.open('test', GD.Test.prototype, ctx, _); // is a private object
    
  • Ahora tengo esta openPrivacy:

    GD.Fabric.openPrivacy = function(func, clss, ctx, _) {
        return function() {
            ctx._ = _;
            var res = clss[func].apply(ctx, arguments);
            ctx._ = null;
            return res;
        };
    };
    
 0
Author: Andreas Dyballa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-20 22:03:20

Esto es lo que hice:

Necesita una clase de código de azúcar que puede encontrar aquí. También soporta protegido, herencia, virtual, cosas estáticas...

;( 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
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
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
Author: snowkid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-10 17:27:20

He creado una nueva herramienta para permitirle tener verdaderos métodos privados en el prototipo https://github.com/TremayneChrist/ProtectJS

Ejemplo:

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
Author: Trem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-29 14:57:51

Tienes que poner un cierre alrededor de tu función constructora real, donde puedes definir tus métodos privados. Para cambiar los datos de las instancias a través de estos métodos privados, debe darles "this" con ellos, ya sea como un argumento de función o llamando a esta función con .aplicar (esto) :

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
Author: Flex Elektro Deimling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-09 14:39:08

Esto es lo que más he disfrutado hasta ahora con respecto a los métodos/miembros privados/públicos y la creación de instancias en javascript:

Aquí está el artículo: http://www.sefol.com/?p=1090

Y aquí está el ejemplo:

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
Author: low_rents,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-10 09:01:44

Sé que es un poco tarde, pero ¿qué tal esto?

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
Author: Maxim Balaganskiy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-28 11:36:38

Ya hay muchas respuestas a esta pregunta, pero nada se ajustaba a mis necesidades. Así que se me ocurrió mi propia solución, espero que sea útil para alguien:

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

Como puede ver, este sistema funciona cuando se usa este tipo de clases en javascript. Por lo que descubrí ninguno de los métodos comentados anteriormente lo hizo.

 0
Author: thegunmaster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-10 18:49:19

Ver esta respuesta para una solución de 'clase' limpia y simple con una interfaz privada y pública y soporte para composición

 0
Author: kofifus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-23 02:08:27

Prefiero almacenar datos privados en un WeakMap asociado. Esto le permite mantener sus métodos públicos en el prototipo donde pertenecen. Esta parece ser la forma más eficiente de manejar este problema para un gran número de objetos.

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
Author: rich remer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-16 19:55:30

No seas tan prolijo. Es Javascript. Utilice una Convención de Nomenclatura .

Después de años de trabajar en clases es6, recientemente comencé a trabajar en un proyecto es5 (usando RequireJS que ya es muy detallado). He estado una y otra vez todas las estrategias mencionadas aquí y todo básicamente se reduce a use una convención de nomenclatura :

  1. Javascript no tiene palabras clave de alcance como private. Otros desarrolladores que ingresen Javascript lo sabrán por adelantado. Pues, una simple convención de nomenclatura es más que suficiente. Una simple convención de nomenclatura de prefijo con un subrayado resuelve el problema de las propiedades privadas y los métodos privados.
  2. Aprovechemos el Prototipo por razones de velocidad, pero no seamos más detallados que eso. Vamos a tratar de mantener la "clase" es5 mirando tan de cerca a lo que podríamos esperar en otros lenguajes de backend (y tratar cada archivo como una clase, incluso si no necesitamos devolver una instancia).
  3. Vamos a demuéstrelo con una situación de módulo más realista (usaremos el antiguo es5 y el antiguo RequireJS).

Mi-descripción.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
Author: prograhammer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-22 23:32:41