Spec-Zone.ru › JavaScript

with

Базовый уровень Ограниченная доступность

Эта функция не является Базовым уровнем, потому что она не работает в некоторых из наиболее широко используемых браузеров.

Устаревший: Эта функция больше не рекомендуется. Хотя некоторые браузеры могут всё ещё поддерживать её, она, возможно, уже была удалена из соответствующих веб-стандартов, находится в процессе исключения или поддерживается только для целей совместимости. Избегайте её использования и обновите существующий код, если это возможно; см. таблицу совместимости внизу этой страницы, чтобы принять решение. Имейте в виду, что эта функция может перестать работать в любой момент.

Примечание: Использование оператора with не рекомендуется, поскольку оно может стать источником запутанных ошибок и проблем совместимости, делает невозможной оптимизацию и запрещено в строгом режиме. Рекомендуемая альтернатива — присвоить объект, к свойствам которого вы хотите получить доступ, временной переменной.

Оператор with расширяет цепочку областей видимости для оператора.

Синтаксис

with (expression)
  statement
expression
Добавляет заданное выражение в цепочку областей видимости, используемую при оценке оператора. Скобки вокруг выражения обязательны.
statement
Любой оператор. Для выполнения нескольких операторов используйте блочный оператор ({ ... }) для их группировки.

Описание

Существует два типа идентификаторов: квалифицированный идентификатор и неквалифицированный идентификатор. Неквалифицированный идентификатор — это тот, который не указывает, откуда он происходит.

foo; // unqualified identifier
foo.bar; // bar is a qualified identifier

Обычно неквалифицированный идентификатор разрешается путем поиска в цепочке областей видимости переменной с этим именем, тогда как квалифицированный идентификатор разрешается путем поиска в цепочке прототипов объекта свойства с этим именем.

const foo = { bar: 1 };
console.log(foo.bar);
// foo is found in the scope chain as a variable;
// bar is found in foo as a property

Одним исключением из этого является глобальный объект, который находится на вершине цепочки областей видимости и чьи свойства автоматически становятся глобальными переменными, на которые можно ссылаться без квалификаторов.

console.log(globalThis.Math === Math); // true

Оператор with добавляет данный объект в начало этой цепочки областей видимости во время выполнения тела оператора. Каждое неквалифицированное имя сначала будет искаться внутри объекта (посредством проверки in), прежде чем искать его в верхней цепочке областей видимости.

Обратите внимание, что если неквалифицированная ссылка относится к методу объекта, метод вызывается с объектом в качестве его значения this.

with ([1, 2, 3]) {
  console.log(toString()); // 1,2,3
}

Объект может иметь свойство [Symbol.unscopables], которое определяет список свойств, которые не должны добавляться в цепочку областей видимости (для обратной совместимости). Дополнительную информацию см. в документации Symbol.unscopables.

Причины использования оператора with включают сохранение одной временной переменной и уменьшение размера файла за счет отказа от повторного использования длинной ссылки на объект. Однако существует гораздо больше причин, по которым операторы with нежелательны:

  • Производительность (Performance): Оператор with заставляет указанный объект сначала искать все имена. Следовательно, все идентификаторы, которые не являются членами указанного объекта, будут находиться медленнее в блоке with. Кроме того, оптимизатор не может делать никаких предположений о том, на что ссылается каждый неквалифицированный идентификатор, поэтому он должен повторять один и тот же поиск свойства каждый раз, когда используется идентификатор.
  • Читаемость (Readability): Оператор with затрудняет принятие решения человеком или компилятором JavaScript о том, будет ли неквалифицированное имя найдено в цепочке областей видимости, и если да, то в каком объекте. Например:

    function f(x, o) {
      with (o) {
        console.log(x);
      }
    }
    

    Если вы посмотрите только на определение f, невозможно сказать, на что ссылается x в теле with. Только когда вызывается f, можно определить, что x является первым формальным параметром o.x или f. Если вы забудете определить x в объекте, который вы передаете в качестве второго параметра, вы не получите ошибку — вместо этого вы получите неожиданные результаты. Также неясно, каково фактическое назначение такого кода.

  • Совместимость с будущими версиями (Forward compatibility): Код, использующий with, может быть не совместим с будущими версиями, особенно если он используется с чем-то, отличным от простого объекта, который может получить больше свойств в будущем. Рассмотрим этот пример:

    function f(foo, values) {
      with (foo) {
        console.log(values);
      }
    }
    

    Если вы вызываете f([1, 2, 3], obj) в среде ECMAScript 5, ссылка values внутри оператора with будет разрешена в obj. Однако ECMAScript 2015 вводит свойство values в Array.prototype (так что оно будет доступно для каждого массива). Таким образом, после обновления среды ссылка values внутри оператора with разрешается в [1, 2, 3].values, и это, вероятно, вызовет ошибки.

    В этом конкретном примере values определяется как не включаемое в область видимости (unscopable) через Array.prototype[Symbol.unscopables], поэтому оно по-прежнему правильно разрешается в параметр values. Если бы оно не было определено как не включаемое в область видимости, можно увидеть, насколько сложной для отладки была бы эта проблема.

Примеры

Использование оператора with

Следующий оператор with указывает, что объект Math является объектом по умолчанию. Операторы, следующие за оператором with, ссылаются на свойство PI и методы cos и sin без указания объекта. JavaScript предполагает объект Math для этих ссылок.

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

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

Как избежать использования оператора with, деструктурируя свойства в текущую область видимости

Обычно вы можете избежать использования with через деструктуризацию свойств. Здесь мы создаем дополнительный блок, чтобы имитировать поведение with, создающего дополнительную область видимости, — но при фактическом использовании этот блок обычно можно опустить.

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

Как избежать использования оператора with с помощью IIFE

Если вы создаете выражение, которое должно многократно использовать длинную ссылку, и ваша цель состоит в том, чтобы исключить это длинное имя внутри вашего выражения, вы можете обернуть выражение в IIFE (НВФВ) и предоставить длинное имя в качестве аргумента.

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

if (((o) => o.foo && !o.bar)(objectHavingAnEspeciallyLengthyName)) {
  // This branch runs.
}

Создание динамических пространств имен с помощью оператора with и прокси

with преобразует каждый поиск переменной в поиск свойства, тогда как Прокси (Proxies) позволяют перехватывать каждый вызов поиска свойства. Вы можете создать динамическое пространство имен, объединив их.

const namespace = new Proxy(
  {},
  {
    has(target, key) {
      // Avoid trapping global properties like `console`
      if (key in globalThis) {
        return false;
      }
      // Trap all property lookups
      return true;
    },
    get(target, key) {
      return key;
    },
  },
);

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

Спецификации

Спецификация
ECMAScript® 2027 Language Specification
# sec-with-statement

Совместимость с браузерами

Десктопные Мобильные Серверные
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android WebView on iOS Bun Deno Node.js
with
1
12
1
4
1
18
4
10.1
1
1.0
4.4
1
1.0.13
1.0
0.10.0

Смотрите также

  • block
  • Строгий режим
  • Symbol.unscopables
  • Array.prototype[Symbol.unscopables]

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API