Start · Sprachen · JavaScript · Referenz · with

with

Anweisung

Die <code>with</code>-Anweisung erweitert die Scope-Kette für eine Anweisung. Ihre Verwendung wird nicht empfohlen und ist im strict mode verboten.

seit JavaScript ES1 (veraltet, im Strict Mode verboten) deprecated seit ja Kategorie: syntax

Signatur

with (expression) statement

Beschreibung

Die with-Anweisung erweitert die Scope-Kette für eine Anweisung.

Es gibt zwei Arten von Bezeichnern: einen qualifizierten und einen unqualifizierten Bezeichner. Ein unqualifizierter Bezeichner gibt nicht an, woher er stammt.

Normalerweise wird ein unqualifizierter Bezeichner aufgelöst, indem die Scope-Kette nach einer Variablen mit diesem Namen durchsucht wird, während ein qualifizierter Bezeichner aufgelöst wird, indem die prototype-Kette eines Objekts nach einer Eigenschaft mit diesem Namen durchsucht wird.

Eine Ausnahme davon ist das global object, das an der Spitze der Scope-Kette steht und dessen Eigenschaften automatisch zu globalen Variablen werden, die ohne Qualifizierer referenziert werden können.

Die with-Anweisung fügt das angegebene Objekt während der Auswertung ihres Anweisungskörpers an den Anfang dieser Scope-Kette ein. Jeder unqualifizierte Name wird zunächst innerhalb des Objekts (über eine in-Prüfung) gesucht, bevor in der oberen Scope-Kette gesucht wird.

Beachten Sie, dass, wenn die unqualifizierte Referenz auf eine Methode des Objekts verweist, die Methode mit dem Objekt als this-Wert aufgerufen wird.

Das Objekt kann eine [Symbol.unscopables]-Eigenschaft besitzen, die eine Liste von Eigenschaften definiert, die nicht zur Scope-Kette hinzugefügt werden sollen (zur Abwärtskompatibilität). Weitere Informationen finden Sie in der Symbol.unscopables-Dokumentation.

Zu den Gründen für die Verwendung einer with-Anweisung gehören das Einsparen einer temporären Variablen und das Reduzieren der Dateigröße durch Vermeidung wiederholter langer Objektreferenzen. Es gibt jedoch weitaus mehr Gründe, warum with-Anweisungen nicht wünschenswert sind:

  • Performance: Die with-Anweisung zwingt dazu, das angegebene Objekt bei allen Namensauflösungen zuerst zu durchsuchen. Daher werden alle Bezeichner, die keine Mitglieder des angegebenen Objekts sind, in einem with-Block langsamer gefunden. Außerdem kann der Optimizer keine Annahmen darüber treffen, worauf sich jeder unqualifizierte Bezeichner bezieht, sodass er bei jeder Verwendung des Bezeichners dieselbe property lookup wiederholen muss.
  • Lesbarkeit: Die with-Anweisung erschwert es einem menschlichen Leser oder JavaScript-Compiler zu entscheiden, ob ein unqualifizierter Name entlang der Scope-Kette gefunden wird, und wenn ja, in welchem Objekt. Wenn Sie sich nur die Definition von f ansehen, ist es unmöglich zu sagen, worauf sich das x im with-Körper bezieht. Erst wenn f aufgerufen wird, kann x als o.x oder als erster formaler Parameter von f bestimmt werden. Wenn Sie vergessen, x im Objekt zu definieren, das Sie als zweiten Parameter übergeben, erhalten Sie keinen Fehler — stattdessen erhalten Sie einfach unerwartete Ergebnisse. Es ist auch unklar, was die eigentliche Absicht eines solchen Codes wäre.
  • Forward-Kompatibilität: Code, der with verwendet, ist möglicherweise nicht vorwärtskompatibel, insbesondere wenn er mit etwas anderem als einem einfachen Objekt verwendet wird, das in Zukunft weitere Eigenschaften erhalten kann. Wenn Sie z.B. f([1, 2, 3], obj) in einer ECMAScript 5-Umgebung aufrufen, wird die values-Referenz innerhalb der with-Anweisung zu obj aufgelöst. ECMAScript 2015 führt jedoch eine values-Eigenschaft auf Array.prototype ein (so dass sie auf jedem Array verfügbar sein wird). Nach dem Upgrade der Umgebung wird die values-Referenz innerhalb der with-Anweisung stattdessen zu [1, 2, 3].values aufgelöst und verursacht wahrscheinlich Fehler. In diesem speziellen Beispiel ist values über Array.prototype[Symbol.unscopables] als unscopable definiert, sodass es immer noch korrekt zum values-Parameter aufgelöst wird. Wäre es nicht als unscopable definiert, wäre dies ein schwer zu debuggendes Problem.

Parameter

Name Typ Default Beschreibung
$expression Pflicht expression Fügt den angegebenen Ausdruck zur Scope-Kette hinzu, die bei der Auswertung der Anweisung verwendet wird. Die Klammern um den Ausdruck sind erforderlich.
$statement Pflicht statement Jede beliebige Anweisung. Um mehrere Anweisungen auszuführen, verwenden Sie eine block-Anweisung ({ ... }), um diese Anweisungen zu gruppieren.

Rückgabewert

Typ
void
Beschreibung
Das with-Statement hat keinen Rückgabewert; es ist eine Kontrollfluss-Anweisung.

Beispiele

Verwendung der with-Anweisung

let a, x, y;
const r = 10;

with (Math) {
  a = PI * r * r;
  x = r * cos(PI);
  y = r * sin(PI / 2);
}

Vermeiden der with-Anweisung durch Destrukturierung von Eigenschaften in den aktuellen Scope

let a, x, y;
const r = 10;

{
  const { PI, cos, sin } = Math;
  a = PI * r * r;
  x = r * cos(PI);
  y = r * sin(PI / 2);
}

Vermeiden der with-Anweisung durch Verwendung eines IIFE

const objectHavingAnEspeciallyLengthyName = { foo: true, bar: false };

if (((o) => o.foo && !o.bar)(objectHavingAnEspeciallyLengthyName)) {
  // Dieser Zweig wird ausgeführt.
}

Erstellen dynamischer Namespaces mit der with-Anweisung und einem Proxy

const namespace = new Proxy(
  {},
  {
    has(target, key) {
      // Vermeide das Abfangen globaler Eigenschaften wie `console`
      if (key in globalThis) {
        return false;
      }
      // Fange alle property lookups ab
      return true;
    },
    get(target, key) {
      return key;
    },
  },
);

with (namespace) {
  console.log(a, b, c); // "a" "b" "c"
}

// Wichtig · Fallstricke

Die Verwendung der `with`-Anweisung wird nicht empfohlen, da sie die Quelle verwirrender Bugs und Kompatibilitätsprobleme sein kann, Optimierungen unmöglich macht und im strict mode verboten ist. Die empfohlene Alternative ist, das Objekt, dessen Eigenschaften Sie zugreifen möchten, einer temporären Variablen zuzuweisen.