Есть ли законное использование оператора «with» в JavaScript?

Комментарии Алана Сторма в ответ на мой ответ относительно Заявление with заставил меня задуматься. Я редко нахожу причину использовать именно эту языковую функцию и никогда особо не задумывался о том, как это может вызвать проблемы. Теперь мне любопытно, как я могу эффективно использовать with, избегая при этом его подводных камней.

В чем вы нашли заявление with полезным?

Никогда не использую. Без этого легче жить, если я сделаю вид, что его не существует.

Nosredna 22.06.2009 22:23

Когда-то у него могло быть много правильных применений. Но это спорный вопрос. ES5 Strict удалил with, так что такого больше нет.

Thomas Aylott 12.04.2010 23:06

Здесь стоит отметить, что ES5 Strict по-прежнему необязательный.

Shog9 21.04.2011 23:38

Вместо удаления «with» в ES5 strict, не лучше ли было бы изменить стандарт, чтобы, если переменная не найдена, любое присвоение, сделанное внутри «with», было привязано к объекту аргумента?

JussiR 07.10.2011 17:04

@JussiR: Наверное. Но проблема в том, что это может сломать работу старых браузеров.

Sune Rasmussen 24.05.2012 17:46

Я нахожу (это) очень полезным, поэтому классы похожи на C++.

QuentinUK 18.03.2015 15:05

Это прекрасный список вещей.

user1228 15.09.2016 18:34
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
380
7
68 414
32

Ответы 32

Visual Basic.NET имеет аналогичный оператор With. Один из наиболее распространенных способов, которыми я его использую, - это быстрое задание ряда свойств. Вместо:

someObject.Foo = ''
someObject.Bar = ''
someObject.Baz = ''

, Я могу написать:

With someObject
    .Foo = ''
    .Bar = ''
    .Baz = ''
End With

Дело не только в лени. Это также делает код более читаемым. И, в отличие от JavaScript, он не страдает двусмысленностью, так как вам нужно добавить префикс . (точка) ко всему, на что влияет этот оператор. Итак, следующие два четко различаются:

With someObject
    .Foo = ''
End With

против.

With someObject
    Foo = ''
End With

Первый - someObject.Foo; последний - Foo в области действия за пределамиsomeObject.

Я считаю, что отсутствие различий в JavaScript делает его гораздо менее полезным, чем вариант Visual Basic, поскольку слишком высок риск двусмысленности. Помимо этого, with по-прежнему является мощной идеей, которая может улучшить читаемость.

Достаточно верно. Однако не отвечает на его вопрос. Так что это не по теме.

Allain Lalonde 20.04.2009 17:28

Это тоже было у меня в голове. кто-то должен был это сказать. Почему в JavaScript не может быть просто точка?

Carson Myers 17.05.2010 00:23

Согласны, точечная нотация лучше, желаю, чтобы JavaScript использовал ее. +1

user2191247 16.12.2015 22:56

Я думаю, что очевидное использование - это ярлык. Если вы, например, инициализируя объект, вы просто экономите, набирая много «ObjectName». Что-то вроде "with-slots" в lisp, которое позволяет писать

(with-slots (foo bar) objectname
   "some code that accesses foo and bar"

что то же самое, что писать

"some code that accesses (slot-value objectname 'foo) and (slot-value objectname 'bar)""

Более очевидно, почему это ярлык, чем когда ваш язык позволяет "Objectname.foo", но все же.

приятно видеть лисп-код! Я думаю, что «with» в javascript, очевидно, вдохновлено его корнями схемы как языка, но, увы, вы получили отрицательное голосование за размещение LISP в вопросе javascript.

Fire Crow 08.04.2010 21:39

Голосование по основному принципу. «with» - феноменально мощная конструкция. Но большинство людей, использующих JS, не понимают замыканий и пишут смехотворно сложные системы наследования классов Java поверх JS - так как же они могли знать о потенциале метапрограммирования, который предлагает «with»?

jared 17.09.2010 21:14

Конечно, with-slots требует, чтобы вы указали, какие слоты вы используете, тогда как with будет использовать любые слоты, которые будут связаны во время выполнения.

Samuel Edwin Ward 21.02.2015 04:41

Имея опыт работы с Delphi, я бы сказал, что использование с должно быть последней возможностью оптимизации размера, возможно, выполняемой каким-то алгоритмом минимизатора javascript с доступом к статическому анализу кода для проверки его безопасности.

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

Оператор VB с лучше тем, что ему нужны точки для устранения неоднозначности области видимости, но оператор Delphi с - это заряженный пистолет с hairtrigger, и мне кажется, что javascript достаточно похож, чтобы гарантировать такое же предупреждение.

Оператор javascript with хуже, чем оператор Delphi. В Delphi with работает так же быстро (если не быстрее), как нотация object.member. В javascript with необходимо пройти по области видимости для проверки совпадающих членов, что всегда делает его медленнее, чем нотация object.member.

Martijn 05.06.2009 17:56

Вы можете определить небольшую вспомогательную функцию, чтобы обеспечить преимущества with без двусмысленности:

var with_ = function (obj, func) { func (obj); };

with_ (object_name_here, function (_)
{
    _.a = "foo";
    _.b = "bar";
});

Боже, МОЯ ГОЛОВА ВЗРЫВАЛАСЬ! без неоднозначность? Должен проголосовать за это, чувак!

Jarrod Dixon 13.02.2009 07:32

@Jarrod: что в этом смешного (is.gd/ktoZ)? Практически все, кто пользуется этим сайтом, умнее меня, так что простите меня, если я ошибаюсь, но это кажется плохой информацией.

raven 23.02.2009 01:32

Но это просто дольше и труднее понять, как это сделать: var _ = obj_name_here; _.a = "foo"; _.b = "бар;

Rene Saarsoo 09.03.2009 13:04

Рене: С этим вы откроете переменную "_" для внешней области видимости, что приведет к потенциальным ошибкам. Он также покажет любые временные переменные, используемые при вычислении параметров объекта.

John Millikin 10.03.2009 07:59

Вы получите больше ошибок из-за того, что with_ является грязной двойной версией (function(_){ _.a = "foo"; })(object_here); (стандартный способ имитации блоков в стиле c / java). Используйте это вместо этого.

mk. 31.01.2010 01:06

Я просто не понимаю, почему использование with более читаемо, чем просто набирать object.member. Я не думаю, что он стал менее читаемым, но и не думаю, что он стал читаемее.

Как сказал lassevk, я определенно вижу, что использование with будет более подвержено ошибкам, чем просто использование очень явного синтаксиса «object.member».

Использование with также замедляет ваш код во многих реализациях, так как теперь все оборачивается дополнительной областью поиска. Нет законной причины для использования with в JavaScript.

Преждевременная оптимизация. Не заявляйте, что «медленнее», если вы не подсчитали; любые накладные расходы, вероятно, тривиальны как для современных, так и для древних js impl.

mk. 31.01.2010 01:11

Я категорически не согласен с вашим выводом, основанным на том, что не может быть проблемой для других разработчиков, кроме вас.

Dave Van den Eynde 12.03.2010 10:34

@mk: хорошо, здесь вам не по себе: var obj = {a:0,b:0,c:0};var d=+new Date;with(obj){for(var i=0;i<1000000;++i){a+=1;b+=1;c+=1}}+new Date-d; дает в среднем 2500, а var obj = {a:0,b:0,c:0};var d=+new Date;for(var i=0;i<1000000;++i){obj.a+=1;obj.b+=1;obj.c+=1}+new Date-d; дает в среднем 750, что делает его использование более чем в 3 раза медленнее.

yorick 23.01.2011 20:24

Я просто запустил их в Chrome 23 в консоли, когда увидел это. Результаты, которые я получил, были 1138 для кода with и 903 без. С этой крошечной разницей даже в тесном цикле я бы сделал выбор, основанный на простоте кодирования и легкости рефакторинга в каждом конкретном случае, прежде чем беспокоиться о производительности.

Plynx 06.01.2013 16:20

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

user = {};
someFunctionThatDoesStuffToUser(user);
someOtherFunction(user);

with(user){
    name = 'Bob';
    age  = 20;
}

Без тщательного исследования этих вызовов функций невозможно определить, в каком состоянии будет находиться ваша программа после выполнения этого кода. Если user.name уже был установлен, теперь это будет Bob. Если он не был установлен, глобальный name будет инициализирован или изменен на Bob, а объект user останется без свойства name.

Ошибки случаются. Если вы используете с, вы в конечном итоге сделаете это и увеличите шансы, что ваша программа потерпит неудачу. Хуже того, вы можете столкнуться с рабочим кодом, который устанавливает глобальное значение в блоке with либо намеренно, либо из-за того, что автор не знает об этой причуде конструкции. Это очень похоже на провал при переключении: вы понятия не имеете, задумал ли автор это, и нет никакого способа узнать, приведет ли «исправление» кода к регрессии.

Современные языки программирования полны функций. Некоторые функции после многих лет использования оказываются плохими, и их следует избегать. Javascript with - один из них.

Эта проблема возникает только тогда, когда вы присваиваете значения атрибуту объекта. Но что, если вы используете его только для чтения значений? Я утверждаю, что в этом случае его можно использовать.

airportyh 22.09.2009 23:33

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

Alan Storm 22.09.2009 23:38

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

airportyh 22.09.2009 23:46

Я думаю, ты можешь быть здесь, Тоби. Мне достаточно проблемы записи, чтобы полностью отказаться от конструкции.

Alan Storm 23.09.2009 20:40
«Это очень похоже на провал на выключателе, ты даже не представляешь ...» -- So then let's ban switch(), too? ;-p
Sz. 13.03.2014 13:18

Вряд ли стоит того, ведь вы можете сделать следующее:

var o = incrediblyLongObjectNameThatNoOneWouldUse;
o.name = "Bob";
o.age = "50";

Для меня это не имело никакого смысла. Хотя я не эксперт в JavaScript

JeroenEijkhof 17.06.2010 22:14

@WmasterJ Для ясности см. Этот пост: yuiblog.com/blog/2006/04/11/with-statement-considered-harmfu‌ l

Dennis 05.08.2010 00:05

Длинные имена переменных - не единственный вариант использования with.

Chris 08.04.2011 01:25

Я думаю, что оператор with может пригодиться при преобразовании языка шаблонов в JavaScript. Например JST в base2, но я видел это чаще.

Я согласен, что это можно запрограммировать без оператора with. Но поскольку это не создает никаких проблем, это законное использование.

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

var sHeader = object.data.header.toString();
var sContent = object.data.content.toString();
var sFooter = object.data.footer.toString();

то вы можете утверждать, что with улучшит читаемость кода, сделав следующее:

var sHeader = null, sContent = null, sFooter = null;
with(object.data) {
    sHeader = header.toString();
    sContent = content.toString();
    sFooter = content.toString();
}

И наоборот, можно утверждать, что вы нарушаете Закон Деметры, но, опять же, возможно, нет. Я отвлекся =).

Прежде всего, знайте, что Дуглас Крокфорд рекомендует нет с использованием with. Я настоятельно рекомендую вам прочитать его сообщение в блоге о with и его альтернативах здесь.

Спасибо за ответ, Том. Я прочитал рекомендацию Крокфорда, и, хотя она имеет смысл, до сих пор далеко. Я прихожу к идее - косвенно затронутой Докманом - что реальная сила with {} заключается в том, как ее можно использовать для управления областью видимости ...

Shog9 07.10.2008 04:18

Сегодня мне пришло в голову другое использование, поэтому я взволнованно поискал в Интернете и нашел существующее упоминание о нем: Определение переменных внутри области видимости блока.

Фон

JavaScript, несмотря на его внешнее сходство с C и C++, не связывает переменные с блоком, в котором они определены:

var name = "Joe";
if ( true )
{
   var name = "Jack";
}
// name now contains "Jack"

Объявление замыкания в цикле - распространенная задача, которая может привести к ошибкам:

for (var i=0; i<3; ++i)
{
   var num = i;
   setTimeout(function() { alert(num); }, 10);
}

Поскольку цикл for не вводит новую область видимости, тот же num - со значением 2 - будет использоваться всеми тремя функциями.

Новый объем: let и with

С введением оператора let в ES6 стало легко ввести новую область видимости, когда это необходимо, чтобы избежать этих проблем:

// variables introduced in this statement 
// are scoped to each iteration of the loop
for (let i=0; i<3; ++i)
{
   setTimeout(function() { alert(i); }, 10);
}

Или даже:

for (var i=0; i<3; ++i)
{
   // variables introduced in this statement 
   // are scoped to the block containing it.
   let num = i;
   setTimeout(function() { alert(num); }, 10);
}

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

for (var i=0; i<3; ++i)
{
   // object members introduced in this statement 
   // are scoped to the block following it.
   with ({num: i})
   {
      setTimeout(function() { alert(num); }, 10);
   }
}

Теперь цикл работает так, как задумано, создавая три отдельные переменные со значениями от 0 до 2. Обратите внимание, что переменные, объявленные в в блоке, не привязаны к нему, в отличие от поведения блоков в C++ (в C переменные должны быть объявлены в начале блок, так что в некотором роде он похож). Это поведение на самом деле очень похоже на Синтаксис блока let, представленное в более ранних версиях браузеров Mozilla, но не получившее широкого распространения в других местах.

Никогда не думал об использовании with с буквальным, кажется законным.

Matt Kantor 20.12.2008 08:47

Это действительно действительно круто. Я никогда не думал о том, чтобы так поиграть с областью видимости JavaScript. Полностью расширил новые области моего кодирования. Хотел бы я проголосовать 10 раз!

kizzx2 22.06.2009 22:28

Для тех, кто все еще против, всегда можно использовать закрытие: for (var i = 0; i < 3; ++i) { setTimeout ((function () { var num = i; return function () { alert (num); }; }) (), 10);}.

Thomas Eding 02.01.2010 20:38

+1 за точку, которую я не рассматривал. Хотел бы я дать дополнительный +1 для <3 в вашем коде.

eyelidlessness 08.04.2010 21:58

Это отличная идея, но не всегда работает в Chrome. См .: jsbin.com/iyopu/edit

Max Shawabkeh 20.04.2010 07:26

Фактически, указанная выше проблема возникает в большинстве браузеров, отличных от Mozilla (Chrome, Safari, Opera, IE).

Max Shawabkeh 20.04.2010 07:43

@Max: да, JavaScript в Firefox преобразует объявление во втором примере в выражение (см .: developer.mozilla.org/En/Core_JavaScript_1.5_Reference/… - «Объявление функции перестает быть таковым, когда оно либо ...»). По-видимому, другие движки JS неправильно улавливают контекст, когда это происходит. Поскольку необходимо выражение, а не объявление, синтаксис из первого примера следует использовать в любом случае.

Shog9 20.04.2010 19:08

Дело в том, что этот пост может предполагать, что with({...}) {...} является универсальной заменой анонимного шаблона закрытия, используемого для скрытия локальных варов. Однако анонимное закрытие правильно захватывает контекст во всех браузерах, в отличие от with.

Max Shawabkeh 20.04.2010 19:14

Эээ, @Max? Анонимное закрытие полностью скрывает определение. Какой бы метод вы ни использовали (with или анонимная функция), вам нужно будет убедиться, что результат вашей функции выражение доступен для внешней области ... при условии, что это то, что вы действительно хотели.

Shog9 20.04.2010 20:47

Верно, но с with объявление функции не работает, даже если оно вызывается внутри области: jsbin.com/iyopu/5/edit

Max Shawabkeh 21.04.2010 05:05

@Max: см. Последний абзац в этом ответе: with и let охватывают только те символы, которые определены в их списке аргументов; JS не имеет области видимости блока, кроме той, которая предоставляется объявлениями функций. Chrome и т. д. Не соблюдают область видимости, введенную with, при преобразовании объявления функции в выражение функции; после появления этой ошибки не имеет значения, откуда функция называется.

Shog9 21.04.2010 09:24

В моем последнем примере «x» находится в списке аргументов как закрытия выражения функции, так и оператора with. Но в одном область соблюдается и должным образом вложена, а в другом - нет. Я так понимаю Почему проблема возникает. Я просто говорю, что следует пояснить, что with не вводит надлежащую область видимости и не может полностью заменить шаблон анонимного закрытия.

Max Shawabkeh 21.04.2010 10:22

@Max: И снова это ошибка в Chrome, которая возникает, когда вы полагаетесь на неявное преобразование объявления в выражение (явные выражения действительно работают). При этом, конечно, with не заменяет закрытие функций. Средство, с помощью которого он вводит область видимости, является более ограниченным значительно, и, конечно, он не предлагает никаких других функций функций. С другой стороны, with не маскирует существующий объект контекста (this) и предлагает более простой синтаксис. Так что для простых задач, таких как те, которые я описал выше, это может быть полезно; а вот как замену функции вряд ли!

Shog9 21.04.2010 17:00

@Max вы можете заставить это работать, используя выражение функции вместо jsbin.com/iyopu/7/edit

Jiaaro 16.06.2010 18:32
позволять statement support in IE would really save my bacon right now, I'm struggling with my conscience on whether or not to use с instead. The real problem is that even with a с as a позволять, extra care still has to be taken because of inherited properties of an object on the prototype chain. For example, var toString = function () { return "Hello"; }; with ({"test":1}) { console.info(toString()); };. In the scope of the с statement, нанизывать() is an inherited property of Объект, so the explicitly defined function isn't called. Still a great answer, though :-)
Andy E 11.10.2010 13:20

вам даже не нужно использовать закрытие. Вы можете передать аргумент функции setTimeout: `for (var i = 0; i <3; ++ i) setTimeout (function (num) {alert (num);}, 10, i);`

gion_13 12.10.2011 13:40

@goin: IE не позволяет передавать аргументы таким образом. IE позволяет вам указать язык сценариев в третьем аргументе для setInterval и setTimeout, любые дополнительные аргументы после этого игнорируются.

Andy E 12.10.2011 14:18

JavaScript 1.7 и ключевое слово let поддерживаются не всеми текущими браузерами, включая Chrome. см. Диаграмма

MarkDav.is 04.05.2012 19:07

если внутри вашего оператора with есть строка a=5, чем она закончится? Анонимный объект? Глобальная переменная? Зависит от того, есть ли в функции var a ? Вы можете по-настоящему фантазировать, но, в конце концов, проблемы с записью заставляют меня никогда не трогать его.

Juan Mendes 02.06.2012 02:16

Это потрясающе, никогда не думал об использовании с таким, но это имеет много смысла и невероятно полезно!

Marcus Stade 21.12.2012 03:52

блокировка области видимости появляется в JavaScript Harmony.

user1637281 10.06.2013 20:16

Не собираюсь задерживать дыхание, но ... Будет хорошо, если это произойдет.

Shog9 10.06.2013 20:17

fyi я считаю, что 'let', использовавшаяся для создания собственного закрывающего блока, теперь устарела

Ben Taliadoros 29.07.2015 13:18

Да, за 7 лет многое изменилось, @Ben - я добавил несколько примечаний, чтобы, надеюсь, уменьшить путаницу, которую это может вызвать. Удивительно, насколько все это недоступно для производственного использования даже спустя много лет.

Shog9 29.07.2015 20:06

Это заставляет меня хотеть, чтобы они сохранили оператор with, потому что, несмотря на его плохую производительность, единственная альтернатива в подобных ситуациях - это исключение строки вашего кода, которая имеет еще худшую производительность.

user7892745 23.04.2017 02:55

Да, да и да. Есть вполне законное использование. Смотреть:

with (document.getElementById("blah").style) {
    background = "black";
    color = "blue";
    border = "1px solid green";
}

По сути, любые другие хуки DOM или CSS отлично подходят для использования с. Это не похоже на то, что «CloneNode» будет неопределенным и вернется в глобальную область видимости, если только вы не сделали все возможное и не решили сделать это возможным.

Жалоба Крокфорда на скорость заключается в том, что новый контекст создается с помощью. Контексты обычно дороги. Я согласен. Но если вы только что создали div и у вас нет под рукой какой-либо инфраструктуры для настройки CSS и вам нужно вручную настроить 15 или около того свойств CSS, то создание контекста, вероятно, будет дешевле, чем создание переменных и 15 разыменований:

var element = document.createElement("div"),
    elementStyle = element.style;

elementStyle.fontWeight = "bold";
elementStyle.fontSize = "1.5em";
elementStyle.color = "#55d";
elementStyle.marginLeft = "2px";

так далее...

+1 поскольку я также думаю, что есть много законных применений with. Однако в этом конкретном случае вы можете просто сделать: element.style.cssText = "background: black ; color: blue ; border: 1px solid green"

GetFree 20.08.2010 12:10

Вы можете добиться того же в одной строке, используя простой метод extend из jQuery или Underscore.js: $.extend(element.style, {fontWeight: 'bold', fontSize: '1.5em', color: '#55d', marginLeft: '2px'}).

Trevor Burnham 15.06.2011 20:09

@TrevorBurnham - Если вы собираетесь предположить, что jQuery доступен, вы должны просто использовать его метод .css() ...

nnnnnn 13.09.2012 09:15

Что именно мешает этим переменным перейти в глобальную область видимости? Просто потому, что все стили CSS всегда определены для всех элементов, или что?

mpen 11.12.2012 20:57

@Mark да, они всегда определены с нулями или пустыми строками в качестве значений, если для свойства нет настраиваемого стиля

Esailija 24.04.2013 23:14

Обоснуйте, пожалуйста, утверждение, что последний пример работает медленнее.

Steven Lu 24.10.2013 23:46

@GetFree Но если это не новый элемент, вы не можете просто установить cssText, обязательно.

Scimonster 01.03.2015 00:46

Я использовал оператор with как простую форму импорта с заданной областью. Допустим, у вас есть какой-то конструктор разметки. Вместо того, чтобы писать:

markupbuilder.div(
  markupbuilder.p('Hi! I am a paragraph!',
    markupbuilder.span('I am a span inside a paragraph')
  )
)

Вместо этого вы можете написать:

with(markupbuilder){
  div(
    p('Hi! I am a paragraph!',
      span('I am a span inside a paragraph')
    )
  )
}

Для этого варианта использования я не выполняю никаких назначений, поэтому у меня нет проблемы неоднозначности, связанной с этим.

Вот как я видел это в VB. (И единственное использование, о котором я знал.)

Mateen Ulhaq 18.06.2011 07:44

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

Adam Thomas 05.11.2012 18:35

Это действительно помогает сократить код для тех, кто работает с путями холста.

Brian McCutchon 16.08.2013 07:59

У меня был пример использования, очень похожий на этот. Мне понадобилось много математических операций. Это: y = Math.root(Math.pow(Match.cos(Math.PI), Math.sin(x))) становится: with (Math) { y = root(pow(cos(PI), sin(x))); }(это, конечно, тупая математика, но для иллюстрации)

asontu 06.02.2015 12:30

Версия этого кода "с" буквально проходит через 240 раз на моей машине медленнее, чем его версия "без". Вот почему люди говорят, что ему нет законного применения. Не потому, что в некоторых местах это не может сделать код красивее. См. Тест: jsfiddle.net/sc46eeyn

Jimbo Jonny 26.10.2015 20:26

@McBrainy - это именно тот тип места, где вы не должны использовать код, который работает намного медленнее (см. Комментарий, который я только что сделал над этим). Если вам нужны ярлыки для суперповторяющегося кода, вы можете объявить их. Например, если вы используете context.bezierCurveTo сто раз подряд, вы можете сказать var bc2 = context.bezierCurveTo;, а затем просто использовать bc2(x,x,etc); каждый раз, когда захотите его вызвать. Это довольно быстро и даже менее многословно, в то время как with очень медленный.

Jimbo Jonny 26.10.2015 20:32

@JimboJonny Проблема с курицей и яйцом ... Я думаю, люди не нашли для этого законного применения. Это только в прошлом приводило к путанице. И именно поэтому движки JS, такие как V8, не имеют для этого оптимизаций.

JustGoscha 16.09.2016 10:46

@JustGoscha - На самом деле это внутренняя проблема, связанная с тем, что вещи внутри оператора with могут ссылаться на разные вещи в зависимости от того, какие переменные / свойства существуют вне оператора with, и это очень затрудняет оптимизацию.

Jimbo Jonny 09.10.2016 21:04

Я никогда не использую, не вижу причин и не рекомендую.

Проблема с with заключается в том, что предотвращает многочисленные лексические оптимизации может выполнять реализация ECMAScript. Учитывая рост быстрых двигателей на основе JIT, этот вопрос, вероятно, станет еще более важным в ближайшем будущем.

Может показаться, что with допускает более чистые конструкции (когда, скажем, вводит новую область видимости вместо общей оболочки анонимной функции или заменяет подробный псевдоним), но это действительно не стоит. Помимо снижения производительности, всегда существует опасность присвоения свойству неправильного объекта (когда свойство не найдено для объекта во внедренной области видимости) и, возможно, ошибочного введения глобальных переменных. IIRC, последняя проблема побудила Крокфорда рекомендовать избегать использования with.

Призрак производительности появляется часто, почти так же часто, как и глобальные вещи ... Всегда кажется мне странным, учитывая, что мы говорим о JavaScript. Вы могли бы предположить, что снижение производительности составляет действительно драматический, чтобы заслужить такое внимание, но ... Если у вас есть какие-либо точные цифры стоимости конструкций with(){}, подобных тем, которые приведены в других ответах здесь, в современных браузерах, мне бы хотелось увидеть их!

Shog9 23.09.2009 09:02

Почему это странно в контексте Javascript? :) И да, это драматично. Подумайте об этом - реализация должна оценить выражение в круглых скобках, преобразовать его в объект, вставить его в начало текущей цепочки областей видимости, оценить оператор внутри блока, а затем восстановить цепочку областей видимости до нормального состояния. Это много работы. Намного больше, чем простой поиск свойств, который можно превратить в высокооптимизированный низкоуровневый код. Вот очень простой тест, который я только что сделал (дайте мне знать, если обнаружите ошибки), демонстрирующий разницу - gist.github.com/c36ea485926806020024

kangax 23.09.2009 09:50

@kangax: Я вырос в C++, где для многих программистов традиционно зацикливается на небольшой эффективности в своем коде, даже если они на самом деле не оказывают заметного влияния на производительность более крупной процедуры или программы. Мне это кажется странным в контексте JavaScript, где такая большая часть производительности подпрограммы может зависеть от реализации виртуальной машины. Я видел несколько случаев, когда программисты JS избегали, скажем, анонимной функции из-за опасений по поводу стоимости установки, но это, похоже, исключение, а не правило, зарезервированное для очень чувствительных областей кода.

Shog9 27.09.2009 19:40

Тем не менее, вы абсолютно правы в отношении стоимости with(){}: установка нового прицела с with стоит очень дорого для каждого браузера, который я тестировал. Вы бы хотели избежать этого в любом коде, вызываемом очень часто. Кроме того, Chrome продемонстрировал поразительный успех для любого кода, выполняемого в рамках with(). Интересно, что IE имел лучшие характеристики производительности для кода в блоках with(): без учета стоимости установки with() обеспечивает самые быстрые средства доступа к участникам в виртуальных машинах IE6 и IE8 (хотя эти виртуальные машины в целом являются самыми медленными). Хороший материал, спасибо ...

Shog9 27.09.2009 19:47

FWIW: вот тот же набор тестов с учетом затрат на установку: jsbin.com/imidu/edit Доступ к переменным для with() почти на порядок медленнее в Chrome и более чем в два раза быстрее в IE ...!

Shog9 27.09.2009 20:01

@kangax - Не правда ли, ты немного недальновиден? @ Shog9 - К счастью, мы говорим о более чистом и гибком языке, javascript, а не об уродливом «высокопроизводительном» языке C++. Теперь, прежде чем вы попробуете какие-либо возражения, знайте, что я уже некоторое время использую C++, и я не совсем новичок.

Christian 06.09.2010 14:06

@ Shog9: Падение скорости Chrome - я думаю, - связано с тем, что V8 сразу переходит к интерпретации из JIT-компиляции, когда достигает определенного уровня сложности по объему и т. д., Например, когда eval() использует вещи. Или, в данном случае, очевидно, при использовании with()

Sune Rasmussen 24.05.2012 18:05

Оператор with может использоваться для уменьшения размера кода или для частных членов класса, например:

// demo class framework
var Class= function(name, o) {
   var c=function(){};
   if ( o.hasOwnProperty("constructor") ) {
       c= o.constructor;
   }
   delete o["constructor"];
   delete o["prototype"];
   c.prototype= {};
   for( var k in o ) c.prototype[k]= o[k];
   c.scope= Class.scope;
   c.scope.Class= c;
   c.Name= name;
   return c;
}
Class.newScope= function() {
    Class.scope= {};
    Class.scope.Scope= Class.scope;
    return Class.scope;
}

// create a new class
with( Class.newScope() ) {
   window.Foo= Class("Foo",{
      test: function() {
          alert( Class.Name );
      }
   });
}
(new Foo()).test();

Оператор with очень полезен, если вы хотите изменить область видимости, что необходимо для вашей собственной глобальной области видимости, которой вы можете управлять во время выполнения. Вы можете добавить к нему константы или некоторые часто используемые вспомогательные функции, например, «toUpper», «toLower» или «isNumber», «clipNumber» aso ..

О плохой производительности я часто читал: определение области действия функции не повлияет на производительность, на самом деле в моем FF функция с областью действия выполняется быстрее, чем функция без области действия:

var o = {x: 5},r, fnRAW= function(a,b){ return a*b; }, fnScoped, s, e, i;
with( o ) {
    fnScoped= function(a,b){ return a*b; };
}

s= Date.now();
r= 0;
for( i=0; i < 1000000; i++ ) {
    r+= fnRAW(i,i);
}
e= Date.now();
console.info( (e-s)+"ms" );

s= Date.now();
r= 0;
for( i=0; i < 1000000; i++ ) {
    r+= fnScoped(i,i);
}
e= Date.now();
console.info( (e-s)+"ms" );

Таким образом, при использовании вышеупомянутого способа оператор with не оказывает отрицательного влияния на производительность, но является хорошим, поскольку снижает размер кода, что влияет на использование памяти на мобильных устройствах.

Это хорошо для помещения кода, который выполняется в относительно сложной среде, в контейнер: я использую его для создания локальной привязки для «окна» и тому подобного для запуска кода, предназначенного для веб-браузера.

Я думаю, что буквальное использование объекта интересно, как замена для использования замыкания

for(var i = nodes.length; i--;)
{
       // info is namespaced in a closure the click handler can access!
       (function(info)
       {           
            nodes[i].onclick = function(){ showStuff(info) };
       })(data[i]);
}

или оператор with, эквивалентный закрытию

for(var i = nodes.length; i--;)
{
       // info is namespaced in a closure the click handler can access!
       with({info: data[i]})
       {           
            nodes[i].onclick = function(){ showStuff(info) };
       }        
}

Я думаю, что реальный риск заключается в случайном минипулировании переменных, которые не являются частью оператора with, поэтому мне нравится, что литерал объекта передается с помощью, вы можете точно увидеть, что он будет в добавленном контексте в коде.

Использование «with» может сделать ваш код более сухим.

Рассмотрим следующий код:

var photo = document.getElementById('photo');
photo.style.position = 'absolute';
photo.style.left = '10px';
photo.style.top = '10px';

Вы можете высушить его до следующего:

with(document.getElementById('photo').style) {
  position = 'absolute';
  left = '10px';
  top = '10px';
}

Думаю, это зависит от того, предпочитаете ли вы разборчивость или выразительность.

Первый пример более разборчив и, вероятно, рекомендуется для большей части кода. Но большая часть кода в любом случае довольно ручная. Второй вариант немного более неясен, но использует выразительную природу языка, чтобы сократить размер кода и лишние переменные.

Я полагаю, что люди, которым нравится Java или C#, выберут первый способ (object.member), а те, кто предпочитает Ruby или Python, выберут второй.

К сожалению, я не понимал, что кто-то уже опубликовал в основном этот же пример год назад. Помимо проблем с производительностью, "with" создает хороший СУХИЙ код за счет того, что его немного труднее читать. Я думаю, что для совместной работы с другими разработчиками или с большей частью производственного кода рекомендуется избегать ключевого слова «with». Но если вы работаете с программистами экспертного уровня и понимаете, как избежать потенциальной неэффективности, то непременно отправляйтесь в город с «с».

Jonah 26.06.2010 11:48

Я создал функцию «слияния», которая устраняет часть этой двусмысленности с помощью оператора with:

if (typeof Object.merge !== 'function') {
    Object.merge = function (o1, o2) { // Function to merge all of the properties from one object into another
        for(var i in o2) { o1[i] = o2[i]; }
        return o1;
    };
}

Я могу использовать его так же, как with, но я знаю, что это не повлияет ни на одну область действия, на которую я не собираюсь влиять.

Использование:

var eDiv = document.createElement("div");
var eHeader = Object.merge(eDiv.cloneNode(false), {className: "header", onclick: function(){ alert("Click!"); }});
function NewObj() {
    Object.merge(this, {size: 4096, initDate: new Date()});
}

Вы можете использовать with, чтобы представить содержимое объекта как локальные переменные для блока, как это делается с этим небольшой шаблонизатор.

Этот метод также используется в _.шаблон() underscore.js.

Peter V. Mørch 15.05.2013 02:20

Вы должны увидеть проверку формы в javascript в W3schools http://www.w3schools.com/js/js_form_validation.asp, где форма объекта "сканируется", чтобы найти вход с именем 'email'

Но я изменил его, чтобы из ЛЮБОЙ формы все поля проверялись как непустые, независимо от имени или количества полей в форме. Я тестировал только текстовые поля.

Но with () упростил задачу. Вот код:

function validate_required(field)
{
with (field)
  {
  if (value==null||value= = "")
    {
    alert('All fields are mandtory');return false;
    }
  else
    {
    return true;
    }
  }
}

function validate_form(thisform)
{
with (thisform)
  {
    for(fiie in elements){
        if (validate_required(elements[fiie])==false){
            elements[fiie].focus();
            elements[fiie].style.border='1px solid red';
            return false;
        } else {elements[fiie].style.border='1px solid #7F9DB9';}
    }

  }
  return false;
}

Недавно я обнаружил, что инструкция with невероятно полезна. Этот метод никогда не приходил мне в голову, пока я не начал свой текущий проект - консоль командной строки, написанную на JavaScript. Я пытался имитировать API консоли Firebug / WebKit, где в консоль можно вводить специальные команды, но они не отменяют никакие переменные в глобальной области. Я подумал об этом, когда пытался решить проблему, о которой упоминал в комментариях к Отличный ответ Shog9.

Чтобы добиться этого эффекта, я использовал два оператора with, чтобы «наслоить» область видимости на глобальную:

with (consoleCommands) {
    with (window) {
        eval(expression); 
    }
}

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

Я был вдохновлен опубликовать этот ответ, когда, к моему удивлению, мне удалось найти ту же технику, которая используется в других местах - Исходный код Chromium!

InjectedScript._evaluateOn = function(evalFunction, object, expression) {
    InjectedScript._ensureCommandLineAPIInstalled();
    // Surround the expression in with statements to inject our command line API so that
    // the window object properties still take more precedent than our API functions.
    expression = "with (window._inspectorCommandLineAPI) { with (window) { " + expression + " } }";
    return evalFunction.call(object, expression);
}

Обновлено: Только что проверил источник Firebug, они цепочка 4 с утверждениями вместе для еще большего количества слоев. Псих!

const evalScript = "with (__win__.__scope__.vars) { with (__win__.__scope__.api) { with (__win__.__scope__.userVars) { with (__win__) {" +
    "try {" +
        "__win__.__scope__.callback(eval(__win__.__scope__.expr));" +
    "} catch (exc) {" +
        "__win__.__scope__.callback(exc, true);" +
    "}" +
"}}}}";

но беспокоиться о том, что ecmascript 5 мешает вам сделать это. Есть ли решение ecmascript 5?

kybernetikos 04.03.2012 21:43

@ Адам: Я не уверен в этом. ES5 выдает ошибку для этого только в строгом режиме, поэтому это не проблема, если строгий режим не объявлен глобально. ES Harmony может представлять большую проблему, но ее можно исправить с помощью некоторых новых вещей, таких как прокси.

Andy E 04.03.2012 21:54

@AndyE, извините, это не по теме, но доступна ли где-нибудь ваша «консоль командной строки, написанная на JavaScript»?

kybernetikos 05.03.2012 22:03

@ Адам: нет, это не так. Все это было задумано как набор инструментов разработчика для гаджетов рабочего стола Windows, но я так и не закончил его (хотя консоль работает очень хорошо). Я мог бы закончить это в какой-то момент, даже если у WDG в данный момент нет очень светлого будущего.

Andy E 06.03.2012 14:07

@AndyE Я пришел с чем-то похожим по той же причине. Теперь область WDG мертва :(

Vitim.us 23.06.2013 00:33

Несколько недель назад мы переместили нашу консольную реализацию в Chrome с with block на некоторую магию символов, потому что with block заблокировал некоторые функции ES6 :)

Alexey Kozyatinskiy 12.03.2016 10:59

@AlexeyKozyatinskiy, о какой символической магии вы имели в виду? 5 лет назад... :)

ADJenks 10.02.2021 21:19

Форк CoffeeScript Коко имеет ключевое слово with, но он просто устанавливает this (также доступный для записи как @ в CoffeeScript / Coco) для целевого объекта внутри блока. Это устраняет двусмысленность и обеспечивает соответствие строгому режиму ES5:

with long.object.reference
  @a = 'foo'
  bar = @b

Для некоторых фрагментов короткого кода я хотел бы использовать тригонометрические функции, такие как sin, cos и т. д., В градусном режиме, а не в лучистом режиме. Для этого я использую объект AngularDegree:

AngularDegree = new function() {
this.CONV = Math.PI / 180;
this.sin = function(x) { return Math.sin( x * this.CONV ) };
this.cos = function(x) { return Math.cos( x * this.CONV ) };
this.tan = function(x) { return Math.tan( x * this.CONV ) };
this.asin = function(x) { return Math.asin( x ) / this.CONV };
this.acos = function(x) { return Math.acos( x ) / this.CONV };
this.atan = function(x) { return Math.atan( x ) / this.CONV };
this.atan2 = function(x,y) { return Math.atan2(x,y) / this.CONV };
};

Затем я могу использовать тригонометрические функции в градусном режиме без дополнительного языкового шума в блоке with:

function getAzimut(pol,pos) {
  ...
  var d = pos.lon - pol.lon;
  with(AngularDegree) {
    var z = atan2( sin(d), cos(pol.lat)*tan(pos.lat) - sin(pol.lat)*cos(d) );
    return z;
    }
  }

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

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

Saket Patel 09.04.2012 23:15

Осознавая проблему масштабирования, я все еще считаю это полезным. Математик, читающий код, хочет непосредственно увидеть, что приведенная выше формула является применением «закона четырех последовательных частей» в сферической тригонометрии. Строгая альтернатива запутывает формулу: z = Math.atan2( Math.sin(d * Math.PI / 180), Math.cos( pol.lat * Math.PI / 180) * Math.tan( pos.lat * Math.PI / 180 ) - Math.sin( pol.lat * Math.PI / 180 ) * Math.cos( d * Math.PI / 180) ) * 180 / Math.PI; даст тот же результат, но это ужас.

rplantiko 10.04.2012 21:40

@rplantiko Следует иметь в виду, что большинству людей это не нравится. Так что, если вы не пишете код, который никто никогда не коснется. Кроме того, я почти уверен, что смогу показать вам пару примеров использования with, которые вас озадачили бы.

Juan Mendes 02.06.2012 01:52

Использование with не рекомендуется и запрещено в строгом режиме ECMAScript 5. Рекомендуемая альтернатива - назначить объект, свойства которого вы хотите получить, временной переменной.

Источник: Mozilla.org

Вот хорошее применение with: добавление новых элементов в литерал объекта на основе значений, хранящихся в этом объекте. Вот пример, который я использовал сегодня:

У меня был набор возможных плиток (с отверстиями сверху, снизу, слева или справа), которые можно было использовать, и мне нужен был быстрый способ добавить список плиток, которые всегда будут размещаться и блокироваться в начале игры. . Я не хотел набирать types.tbr для каждого типа в списке, поэтому просто использовал with.

Tile.types = (function(t,l,b,r) {
  function j(a) { return a.join(' '); }
  // all possible types
  var types = { 
    br:  j(  [b,r]),
    lbr: j([l,b,r]),
    lb:  j([l,b]  ),  
    tbr: j([t,b,r]),
    tbl: j([t,b,l]),
    tlr: j([t,l,r]),
    tr:  j([t,r]  ),  
    tl:  j([t,l]  ),  
    locked: []
  };  
  // store starting (base/locked) tiles in types.locked
  with( types ) { locked = [ 
    br,  lbr, lbr, lb, 
    tbr, tbr, lbr, tbl,
    tbr, tlr, tbl, tbl,
    tr,  tlr, tlr, tl
  ] } 
  return types;
})("top","left","bottom","right");

Вы можете использовать with, чтобы избежать явного управления арностью при использовании require.js:

var modules = requirejs.declare([{
    'App' : 'app/app'
}]);

require(modules.paths(), function() { with (modules.resolve(arguments)) {
    App.run();
}});

Реализация requirejs.declare:

requirejs.declare = function(dependencyPairs) {
    var pair;
    var dependencyKeys = [];
    var dependencyValues = [];

    for (var i=0, n=dependencyPairs.length; i<n; i++) {
        pair = dependencyPairs[i];
        for (var key in dependencyPairs[i]) {
            dependencyKeys.push(key);
            dependencyValues.push(pair[key]);
            break;
        }
    };

    return {
        paths : function() {
            return dependencyValues;
        },
    
        resolve : function(args) {
            var modules = {};
            for (var i=0, n=args.length; i<n; i++) {
                modules[dependencyKeys[i]] = args[i];
            }
            return modules;
        }
    }   
}

Как отметил Энди Э в комментариях к ответу Shog9, это потенциально неожиданное поведение возникает при использовании with с литералом объекта:

for (var i = 0; i < 3; i++) {
  function toString() {
    return 'a';
  }
  with ({num: i}) {
    setTimeout(function() { console.info(num); }, 10);
    console.info(toString()); // prints "[object Object]"
  }
}

Не то чтобы неожиданное поведение не было отличительной чертой with.

Если вы действительно хотите использовать эту технику, по крайней мере используйте объект с нулевым прототипом.

function scope(o) {
  var ret = Object.create(null);
  if (typeof o !== 'object') return ret;
  Object.keys(o).forEach(function (key) {
    ret[key] = o[key];
  });
  return ret;
}

for (var i = 0; i < 3; i++) {
  function toString() {
    return 'a';
  }
  with (scope({num: i})) {
    setTimeout(function() { console.info(num); }, 10);
    console.info(toString()); // prints "a"
  }
}

Но это будет работать только в ES5 +. Также не используйте with.

Я работаю над проектом, который позволит пользователям загружать код для изменения поведения частей приложения. В этом сценарии я использовал предложение with, чтобы их код не изменял что-либо за пределами области действия, с которой я хочу, чтобы они возились. (Упрощенная) часть кода, которую я использую для этого:

// this code is only executed once
var localScope = {
    build: undefined,

    // this is where all of the values I want to hide go; the list is rather long
    window: undefined,
    console: undefined,
    ...
};
with(localScope) {
    build = function(userCode) {
        eval('var builtFunction = function(options) {' + userCode + '}');
        return builtFunction;
    }
}
var build = localScope.build;
delete localScope.build;

// this is how I use the build method
var userCode = 'return "Hello, World!";';
var userFunction = build(userCode);

Этот код гарантирует (отчасти), что пользовательский код не имеет доступа ни к каким объектам с глобальной областью видимости, таким как window, ни к какой-либо из моих локальных переменных через замыкание.

Как слово для мудрых, мне все еще нужно выполнять статические проверки кода для кода, отправленного пользователем, чтобы убедиться, что они не используют другие хитрые методы для доступа к глобальной области. Например, следующий пользовательский код получает прямой доступ к window:

test = function() {
     return this.window
};
return test();

Связанный: stackoverflow.com/questions/543533/…

Shog9 04.11.2014 07:25

Просто хотел добавить, что вы можете получить функциональность with () с красивым синтаксисом и без двусмысленности с вашим собственным умным методом ...

     //utility function
  function _with(context){
           var ctx=context;
           this.set=function(obj){
             for(x in obj){
                //should add hasOwnProperty(x) here
                ctx[x]=obj[x];
             }
       } 

       return this.set;          
 }

 //how calling it would look in code...

  _with(Hemisphere.Continent.Nation.Language.Dialect.Alphabet)({

      a:"letter a",
      b:"letter b",
      c:"letter c",
      d:"letter a",
      e:"letter b",
      f:"letter c",
     // continue through whole alphabet...

  });//look how readable I am!!!!

..или если вы В самом деле хотите использовать "with ()" без двусмысленности и без специального метода, заключите его в анонимную функцию и используйте .call

//imagine a deeply nested object 
//Hemisphere.Continent.Nation.Language.Dialect.Alphabet
(function(){
     with(Hemisphere.Continent.Nation.Language.Dialect.Alphabet){ 
         this.a = "letter a";
         this.b = "letter b";
         this.c = "letter c";
         this.d = "letter a";
         this.e = "letter b";
         this.f = "letter c";
         // continue through whole alphabet...
     }
}).call(Hemisphere.Continent.Nation.Language.Dialect.Alphabet)

Однако, как отмечали другие, это несколько бессмысленно, поскольку вы можете ...

 //imagine a deeply nested object Hemisphere.Continent.Nation.Language.Dialect.Alphabet
     var ltr=Hemisphere.Continent.Nation.Language.Dialect.Alphabet 
     ltr.a = "letter a";
     ltr.b = "letter b";
     ltr.c = "letter c";
     ltr.d = "letter a";
     ltr.e = "letter b";
     ltr.f = "letter c";
     // continue through whole alphabet...

Мой

switch(e.type) {
    case gapi.drive.realtime.ErrorType.TOKEN_REFRESH_REQUIRED: blah
    case gapi.drive.realtime.ErrorType.CLIENT_ERROR: blah
    case gapi.drive.realtime.ErrorType.NOT_FOUND: blah
}

сводится к

with(gapi.drive.realtime.ErrorType) {switch(e.type) {
    case TOKEN_REFRESH_REQUIRED: blah
    case CLIENT_ERROR: blah
    case NOT_FOUND: blah
}}

Можно ли доверять такому некачественному коду? Нет, мы видим, что его сделали абсолютно нечитаемым. Этот пример неоспоримо доказывает, что нет необходимости в with-statement, если я правильно понимаю удобочитаемость;)

использование оператора with с прокси-объектами

Недавно я хочу написать плагин для вавилон, который включает макросы. Я хотел бы иметь отдельное пространство имен переменных, в котором хранятся мои макропеременные, и я могу запускать свои макрокоды в этом пространстве. Кроме того, я хочу обнаруживать новые переменные, которые определены в кодах макросов (потому что это новые макросы).

Сначала я выбираю модуль vm, но я обнаружил, что глобальные переменные в модуле vm, такие как Array, Object и т. д., Отличаются от основной программы, и я не могу реализовать module и require, которые будут полностью совместимы с этими глобальными объектами (потому что я не могу реконструировать основные модули). В конце концов, я нахожу утверждение «с».

const runInContext = function(code, context) {
    context.global = context;
    const proxyOfContext = new Proxy(context, { has: () => true });
    let run = new Function(
        "proxyOfContext",
        `
            with(proxyOfContext){
                with(global){
                        ${code}
                }
            }
        `
    );
    return run(proxyOfContext);
};

Этот прокси-объект перехватывает поиск всех переменных и говорит: «Да, у меня есть эта переменная». и Если у прокси-объекта действительно нет этой переменной, покажите ее значение как undefined.

Таким образом, если какая-либо переменная определена в макросе code с помощью оператора var, я могу найти ее в объекте контекста (например, в модуле vm). Но переменные, определенные с помощью let или const, доступны только в это время и не будут сохранены в объекте контекста (модуль vm сохраняет их, но не раскрывает их).

Спектакль: Производительность этого метода лучше, чем vm.runInContext.

безопасность: если вы хотите запустить код в песочнице, это ни в коем случае не безопасно, и вы должны использовать модуль vm. Он предоставляет только новое пространство имен.

Связанный мой вопрос: Является ли использование оператора with с прокси плохой практикой?

FZs 13.01.2021 12:47

Другие вопросы по теме