Существуют ли законные варианты использования оператора «with» в JavaScript? - PullRequest
361 голосов
/ 14 сентября 2008

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

Где вы нашли выражение with полезным?

Ответы [ 31 ]

7 голосов
/ 26 июня 2010

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

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

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, выберут второй.

6 голосов
/ 14 сентября 2008

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

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

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

6 голосов
/ 14 сентября 2008

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

(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", но все же.

5 голосов
/ 24 октября 2012

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

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

4 голосов
/ 05 февраля 2010

Оператор 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.log( (e-s)+"ms" );

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

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

3 голосов
/ 15 сентября 2008

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

3 голосов
/ 12 августа 2010

Я создал функцию «слияния», которая устраняет эту двусмысленность с помощью оператора 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()});
}
3 голосов
/ 08 апреля 2010

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

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, поэтому мне нравится объектный литерал, передаваемый в, вы можете точно видеть, что это будет в добавленном контексте в коде.

3 голосов
/ 09 апреля 2012

Для некоторых коротких фрагментов кода я хотел бы использовать тригонометрические функции, такие как 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;
    }
  }

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

3 голосов
/ 15 сентября 2008

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

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

...