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"
}
Спецификации
Совместимость с браузерами
| Десктопные | Мобильные | Серверные | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 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 |
Смотрите также
© 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