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

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

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

Ответы [ 31 ]

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

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

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

2 голосов
/ 07 октября 2008

Я думаю, что полезность 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 и его альтернатив здесь .

2 голосов
/ 04 апреля 2010

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

1 голос
/ 08 сентября 2010

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

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

Но с помощью () все стало проще. Вот код:

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;
}
1 голос
/ 15 июня 2011

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

with long.object.reference
  @a = 'foo'
  bar = @b
0 голосов
/ 05 июня 2016

Мой

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, если я правильно понимаю читаемость;)

0 голосов
/ 17 апреля 2015

Просто хотел добавить, что вы можете получить функциональность "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...
0 голосов
/ 03 ноября 2014

Я работаю над проектом, который позволит пользователям загружать код для изменения поведения частей приложения. В этом сценарии я использовал предложение 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();
0 голосов
/ 25 апреля 2014

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

for (var i = 0; i < 3; i++) {
  function toString() {
    return 'a';
  }
  with ({num: i}) {
    setTimeout(function() { console.log(num); }, 10);
    console.log(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.log(num); }, 10);
    console.log(toString()); // prints "a"
  }
}

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

0 голосов
/ 25 сентября 2013

Вы можете использовать с, чтобы избежать необходимости явно управлять арностью при использовании 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;
        }
    }   
}
...