Private JavaScript-Methoden

  • Um eine JavaScript-Klasse mit einer öffentlichen Methode zu erstellen, würde ich Folgendes tun:

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

    Auf diese Weise können Benutzer meiner Klasse:

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

    Wie erstelle ich eine private Methode, die dies ermöglicht? von den Methoden buy_food und use_restroom aufgerufen werden, von Benutzern der Klasse jedoch nicht extern?

    Mit anderen Worten, ich möchte, dass meine Methodenimplementierung Folgendes ausführt:

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

    Das sollte jedoch nicht funktionieren:

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

    Wie definiere ich private_stuff als private Methode, also gelten beide als richtig?

    habe ich gelesen < a href = "http://javascript.crockford.com/private.html" rel = "noreferrer"> Doug Crockfords Schreibweise einige Male, aber es scheint nicht, als könnten "private" Methoden von der Öffentlichkeit aufgerufen werden Methoden und "privilegierte" Methoden können extern aufgerufen werden.

    07 June 2017
    John SlegersJon Adams
28 answers
  • Sie können es, aber der Nachteil ist, dass es nicht Teil des Prototyps sein kann:

     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();
        }
    }
     
    11 September 2008
    17 of 26
  • Sie können private Methoden wie folgt simulieren:

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

    Weitere Informationen zu dieser Technik finden Sie hier: http://webreflection.blogspot.com/2008/04/natural -javascript-private-Methods.html

    07 February 2012
    georgebrock
  • Verwenden der Selbstaufruffunktion und des Aufrufs

    JavaScript verwendet Prototypen und hat keine Klassen (oder Methoden für diese Angelegenheit) wie objektorientierte Sprachen. Ein JavaScript-Entwickler muss in JavaScript denken.

    Wikipedia-Zitat:

    Im Gegensatz zu vielen objektorientierten Sprachen Es gibt keinen Unterschied zwischen einer Funktionsdefinition und einer Methodendefinition. Die Unterscheidung tritt vielmehr während des Funktionsaufrufs auf; Wenn eine Funktion als Methode eines Objekts aufgerufen wird, ist das lokale Schlüsselwort this dieser Funktion an das Objekt für diesen Aufruf gebunden.

    Lösung mit einer selbstaufrufenden Funktion und der Funktion aufrufen , um die private" Methode "aufzurufen:

     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
     

    Die Aufruffunktion ermöglicht den Aufruf der privaten Funktion mit dem entsprechenden Kontext (this).


    Einfacher mit Node.js

    Wenn Sie node.js verwenden, ist dies nicht der Fall Sie benötigen das IIFE , da Sie die Modulladesystem :

     function MyObject (foo) {
        this._foo = foo;
    }
    
    function privateFun (prefix) {
        return prefix + this._foo;
    }
    
    MyObject.prototype.publicFun = function () {
        return privateFun.call(this, '>>');
    }
    
    exports.MyObject = MyObject;
     

    Laden Sie die Datei:

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


    (experimentell) ES7 mit dem Bind-Operator

    Der Bindungsoperator :: ist ein ECMAScript-Vorschlag und ist in Babel implementiert (

24 September 2016
Yves M.benz001
  • Wenn Sie in diesen Situationen über eine öffentliche API verfügen und private und öffentliche Methoden / Eigenschaften wünschen, verwende ich immer das Modulmuster. Dieses Muster wurde in der YUI-Bibliothek populär gemacht. Die Details finden Sie hier:

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

    Es ist wirklich unkompliziert und für andere Entwickler leicht zu verstehen. Für ein einfaches Beispiel:

     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
     
    11 September 2008
  • Hier ist die Klasse, die ich erstellt habe, um zu verstehen, was Douglas Crockford auf seiner Website vorgeschlagen hat Private Mitglieder in 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
    
    }
     
    05 October 2012
    Lorenzo PolidoriLa Chamelle
  • Ich habe mir folgendes beschworen: EDIT: Eigentlich hat jemand eine identische Lösung gefunden. 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!'
     
    01 September 2009
  • Ich denke, dass solche Fragen immer wieder auftauchen, weil die Schließungen nicht verstanden werden. Schlösser sind in JS das Wichtigste. Jeder JS-Programmierer muss die Essenz davon spüren.

    1. Zunächst müssen wir einen gesonderten Geltungsbereich (Abschluss) festlegen.

    function () {
    
    }
     

    2. In diesem Bereich können wir tun, was wir wollen. Und niemand wird davon erfahren.

    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. Für die Welt Wissen Sie über unsere Restaurantklasse, müssen wir sie von der Schließung zurückgeben.

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

    4. Am Ende haben wir:

    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. Dieser Ansatz hat auch Vererbungs- und Vorlagenpotenzial.

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

    Ich hoffe, das hilft jemandem, dieses Thema besser zu verstehen

    14 August 2013
    imosWes McKinney
  • Alle diese Schließung kostet Sie. Stellen Sie sicher, dass Sie die Auswirkungen auf die Geschwindigkeit besonders im IE testen. Sie werden feststellen, dass es Ihnen mit einer Namenskonvention besser geht. Es gibt immer noch viele Internetbenutzer, die gezwungen sind, IE6 zu verwenden ...

    15 September 2008
    KeithS
  • Ich persönlich bevorzuge das folgende Muster zum Erstellen von Klassen in 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(); }
            ...
        };
    })();
     

    Wie Sie Wie Sie sehen, können Sie sowohl Klassen- als auch Instanzeneigenschaften definieren, von denen jede öffentlich und privat sein kann.


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

    Siehe auch diese Geige .

    08 June 2017
    John SlegersJon Adams
  • Nehmen Sie eine der Lösungen, die Crockfords private oder privilegierten -Muster folgen. Zum Beispiel:

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

    In jedem Fall, in dem der Angreifer in seinem JS-Kontext kein Recht zum Ausführen hat Kein Zugriff auf "öffentliche" oder "private" Felder oder Methoden. Falls der Angreifer über diesen Zugriff verfügt, kann er diesen One-Liner ausführen:

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

    Beachten Sie den obigen Code ist generisch für alle Konstruktortypen. Bei einigen der Lösungen wird es hier nicht funktionieren, aber es sollte klar sein, dass so ziemlich alle Lösungen, die auf dem Verschluss basieren, mit verschiedenen replace() -Parametern auf diese Weise gebrochen werden können.

    Nachdem dies ausgeführt wurde, verfügt jedes mit new Foo() erstellte Objekt über eine eval -Methode, die aufgerufen werden kann, um Werte oder Methoden zurückzugeben oder zu ändern, die im Konstruktorabschluss definiert sind. ZB:

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

    Das einzige Problem, das ich hier sehen kann, ist, dass es für Fälle, in denen es vorhanden ist, nicht funktioniert nur eine Instanz und wird beim Laden erstellt. Dann gibt es jedoch keinen Grund, einen Prototyp zu definieren. In diesem Fall kann der Angreifer das Objekt statt des Konstruktors einfach neu erstellen, sofern er die gleichen Parameter übergeben kann (z. B. sie sind konstant oder werden aus verfügbaren Werten berechnet).

    Meiner Meinung nach macht Crockfords Lösung so gut wie nutzlos. Da die "Privatsphäre" leicht die Nachteile seiner Lösung durchbricht (reduzierte Lesbarkeit & amp; Wartbarkeit, verringerte Leistung, mehr Speicher) macht die auf Prototypen basierende Methode ohne Privatsphäre die bessere Wahl.

    Normalerweise verwende ich führende Unterstriche zum Markieren von __private und _protected Methoden und Feldern (Perl-Stil), aber die Vorstellung, Privatsphäre in JavaScript zu haben, zeigt nur, wie es falsch verstanden wird Sprache.

    Deshalb stimme ich nicht mit Crockford überein

    18 August 2014
    Fozi