564 Stimmen

Private Eigenschaften in JavaScript ES6 Klassen

Ist es möglich, private Eigenschaften in ES6-Klassen zu erstellen?

Hier ist ein Beispiel. Wie kann ich den Zugriff auf instance.property verhindern?

class Something {
  constructor(){
    this.property = "test";
  }
}

var instance = new Something();
console.log(instance.property); //=> "test"

30voto

loganfsmyth Punkte 146387

Der einzige Weg, um echte Privatsphäre in JS zu erreichen, ist durch Scoping, sodass es keine Möglichkeit gibt, eine Eigenschaft, die ein Mitglied von this ist, die nur innerhalb des Components zugänglich ist. Der beste Weg, um wirklich private Daten in ES6 zu speichern, ist mit einem WeakMap.

const privateProp1 = new WeakMap();
const privateProp2 = new WeakMap();

class SomeClass {
  constructor() {
    privateProp1.set(this, "Ich bin privat1");
    privateProp2.set(this, "Ich bin privat2");

    this.publicVar = "Ich bin öffentlich";
    this.publicMethod = () => {
      console.log(privateProp1.get(this), privateProp2.get(this))
    };        
  }

  printPrivate() {
    console.log(privateProp1.get(this));
  }
}

Offensichtlich ist dies wahrscheinlich langsam und definitiv hässlich, aber es bietet Privatsphäre.

Denken Sie daran, dass AUCH DAS nicht perfekt ist, weil Javascript so dynamisch ist. Jemand könnte immer noch

var oldSet = WeakMap.prototype.set;
WeakMap.prototype.set = function(key, value){
    // Speichere 'this', 'key' und 'value'
    return oldSet.call(this, key, value);
};

um Werte abzufangen, während sie gespeichert werden, also wenn Sie besonders vorsichtig sein möchten, müssten Sie eine lokale Referenz auf .set und .get erfassen, um explizit anstatt auf dem überdeckbaren Prototypen zu vertrauen.

const {set: WMSet, get: WMGet} = WeakMap.prototype;

const privateProp1 = new WeakMap();
const privateProp2 = new WeakMap();

class SomeClass {
  constructor() {
    WMSet.call(privateProp1, this, "Ich bin privat1");
    WMSet.call(privateProp2, this, "Ich bin privat2");

    this.publicVar = "Ich bin öffentlich";
    this.publicMethod = () => {
      console.log(WMGet.call(privateProp1, this), WMGet.call(privateProp2, this))
    };        
  }

  printPrivate() {
    console.log(WMGet.call(privateProp1, this));
  }
}

22voto

Zur zukünftigen Referenz für andere Interessierte: Es wird nun empfohlen, WeakMaps zur Speicherung privater Daten zu verwenden.

Hier ist ein klareres, funktionierendes Beispiel:

function storePrivateProperties(a, b, c, d) {
  let privateData = new WeakMap;
  // Eindeutiges Objekt als Schlüssel, WeakMap kann nur Objekte als Schlüssel akzeptieren. Wenn der Schlüssel nicht mehr referenziert wird, sammelt der Garbage Collector den Schlüssel-Wert
  let keyA = {}, keyB = {}, keyC = {}, keyD = {};

  privateData.set(keyA, a);
  privateData.set(keyB, b);
  privateData.set(keyC, c);
  privateData.set(keyD, d);

  return {
    logPrivateKey(key) {
      switch(key) {
      case "a":
        console.log(privateData.get(keyA));
        break;
      case "b":
        console.log(privateData.get(keyB));
        break;
      case "c":
        console.log(privateData.get(keyC));
        break;
      case "d":
        console.log(privateData.set(keyD));
        break;
      default:
        console.log(`Es gibt keinen Wert für ${key}`)
      }
    }
  }
}

12voto

Bergi Punkte 565633

Je nach wem du fragst :-)

Es gibt kein private-Eigenschaftsmodifizierer im Maximal minimalistische Klassen-Vorschlag, der anscheinend in den aktuellen Entwurf übernommen wurde.

Es könnte jedoch Unterstützung für private Namen geben, die die Verwendung von privaten Eigenschaften ermöglichen - und sie könnten wahrscheinlich auch in Klassendefinitionen verwendet werden.

10voto

Johnny Oshika Punkte 49503

Die Verwendung von ES6-Modulen (initial von @d13 vorgeschlagen) funktioniert gut für mich. Es imitiert private Eigenschaften nicht perfekt, aber zumindest können Sie sicher sein, dass Eigenschaften, die privat sein sollten, nicht außerhalb Ihrer Klasse durchsickern. Hier ist ein Beispiel:

something.js

let _message = null;
const _greet = name => {
  console.log('Hallo ' + name);
};

export default class Something {
  constructor(message) {
    _message = message;
  }

  say() {
    console.log(_message);
    _greet('Bob');
  }
};

Dann kann der konsumierende Code so aussehen:

import Something from './something.js';

const something = new Something('Sonniger Tag!');
something.say();
something._message; // undefined
something._greet(); // Ausnahme

Update (Wichtig):

Wie @DanyalAytekin in den Kommentaren erläutert hat, sind diese privaten Eigenschaften statisch und daher global im Umfang. Sie funktionieren gut bei der Arbeit mit Singleton-Instanzen, aber Vorsicht ist geboten bei transienten Objekten. Erweitern wir das obige Beispiel:

import Something from './something.js';
import Something2 from './something.js';

const a = new Something('a');
a.say(); // a

const b = new Something('b');
b.say(); // b

const c = new Something2('c');
c.say(); // c

a.say(); // c
b.say(); // c
c.say(); // c

9voto

Lucio Paiva Punkte 15969

Ein anderer Ansatz für "privat"

Anstatt gegen die Tatsache anzukämpfen, dass private Sichtbarkeit in ES6 derzeit nicht verfügbar ist, habe ich mich entschieden, einen praktischeren Ansatz zu wählen, der gut funktioniert, wenn Ihre IDE JSDoc unterstützt (z.B. Webstorm). Die Idee ist, das @private-Tag zu verwenden. Was die Entwicklung betrifft, wird die IDE verhindern, dass Sie von außerhalb der Klasse auf private Elemente zugreifen. Für mich funktioniert das ziemlich gut und es ist wirklich nützlich, interne Methoden zu verbergen, damit mir die Autovervollständigung nur das zeigt, was die Klasse wirklich freigeben sollte. Hier ist ein Beispiel:

Autovervollständigung zeigt nur öffentliche Inhalte

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X