Параметры проверки Javascript для нулевого значения

Я пишу функцию, которая проверяет, являются ли аргументы равными нулю, и похоже, что они не работают корректно. Примечание. Использование Chrome в качестве моего браузера, но этот код должен поддерживаться в кросс-браузере.

// check all arguments, and make sure they aren't zero

function zeroCheck(arg1, arg2) {
    var i, argsLen = arguments.length;
    for (i = 0; i <= argsLen; i += 1) {
        if (arguments[i] === 0) {
            // This is where it doesn't behave as I expected
            arguments[i] = 1; // make arg1 = 1
        }
    }
    console.log(arg1); // arg1 = 0
}

zeroCheck(0, 2);

Я ожидал, что arg1 будет равен 1, но он все равно равен 0.

Ответ 1

Несмотря на то, что некоторые браузеры работают так, как вы хотите (Chrome и Firefox), мне не видно из спецификации ECMAScript, что это всегда будет так. Это заставляет это звучать, как массив аргументов, вероятно, просто ссылка на именованные аргументы в нестрогом режиме, и в нем конкретно говорится, что они не должны иметь никакого соединения друг с другом в строгом режиме (другими словами, то, что вы хотите сделать, конкретно НЕ должен работать в строгом режиме).

Вы можете увидеть в этом jsFiddle http://jsfiddle.net/jfriend00/bG5xp/, что Chrome, похоже, реализует его, как описывает спецификация. Существует связь между arguments[0] и arg1 в нестандартном режиме, и нет связи между ними в строгом режиме. Тщательное прочтение спецификации не говорит о том, что javascript должен иметь связь между двумя в нестрогом режиме, но это действительно похоже на то, что это похоже. Если вы хотите положиться на это, и вы были уверены, что никогда не нуждаетесь в том, чтобы ваш код работал в строгом режиме, вам придется протестировать кучу браузеров, чтобы узнать, поддерживается ли ваше поведение.

Также неясно из спецификации, если массив аргументов всегда должен быть модифицируемым, хотя это кажется более вероятным, учитывая, что он реализован с объектом javascript (а не с фактическим массивом).

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

Общим способом создания копии массива аргументов является:

var args = Array.prototype.slice.call(arguments, 0);

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

Ответ 2

Попробуй так. arg1 со значением 0 оценивается как false/falsy, поэтому вы можете использовать эту краткую булевую оценку:

function zeroCheck(arg1,arg2) {
    arg1 = arg1 || 1; 
    console.log(arg1); //=> 1
}

zeroCheck(0,2);

Общая функция для проверки всех аргументов (возвращает Array)

function zeroCheckArgs(args){
  return [].slice.call(args).map(function(a){return a || 1;});
}

//more conservative
function zeroCheckArgsAlt(args){
  var retArgs = [];
  for (var i=0;i<args.length;i+=1){
    retArgs.push(args[i] || 1);
  }
  return retArgs;
}

function some(){
  var args = zeroCheckArgs(arguments);
  console.log(args);
}

function someAlt(){
  var args = zeroCheckArgsAlt(arguments);
  console.log(args);
}

some(1,0,0,12,12,14,0,1);    //=> [1, 1, 1, 12, 12, 14, 1, 1]
someAlt(1,0,0,12,12,14,0,1); //=> [1, 1, 1, 12, 12, 14, 1, 1]

Ответ 3

Из спецификации ECMA-262:

"Для функций нестрого режима индекс массива (определенный в 15.4) именованные свойства данных объекта аргументов, числовые значения которых меньше числа формальных параметров соответствующего функционального объекта, сначала разделяют их значения с соответствующим аргументом привязки в контексте выполнения функций. Это означает, что изменение свойства изменяет соответствующее значение привязки аргумента и наоборот. Это соответствие нарушается, если такое свойство удаляется, а затем переопределяется или свойство изменяется в свойство accessor. Для функций строгого режима значения свойств объекта аргументов являются просто копией аргументов, переданных функции, и между значениями свойств и формальными значениями параметров нет динамической связи."

Но если вы прочтете технические подробности о том, как установлен объект arguments, я думаю, вы обнаружите, что он основан на том, сколько аргументов фактически передано функции при ее вызове, а не о том, сколько объявленных аргументов объявлено, поэтому использование arguments и цикл для проверки значения каждого именованного параметра могут не работать, если они не все переданы. Хотя в вашем случае, если вы специально тестируете для 0, он должен работать, поскольку параметры, которые не будет undefined, а не 0.

Сказав это, именно то, как фактически ведет себя объект arguments, зависит от браузера. Chrome не соответствует спецификации.

Ответ 5

@nnnnnn -

"Для нестрогих функций режима индекс массива (определенный в 15.4), названный свойства данных объекта аргументов, числовые значения которых указаны меньше, чем число формальных параметров соответствующих Первоначально объект функции сначала делится своими значениями с соответствующим привязки аргументов в контексте выполнения функций. Это значит, что изменение свойства изменяет соответствующее значение аргумента и наоборот. Это соответствие нарушается, если такое свойство удаляется, а затем переопределяется или изменяется свойство в свойство accessor. Для функций строгого режима значения свойства объекта arguments являются просто копией аргументов передается функции, и динамическая связь между значения свойств и формальные значения параметров."

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

// check all arguments, and make sure they aren't zero

function zeroCheck(arg1,arg2) {
    var i, argsLen = arguments.length;
    for (i = 0; i <= argsLen; i += 1) {
        if (arguments[i] === 0) {
            // This is where it doesn't behave as I expected
            arguments[i] = 1; // make arg1 = 1
        }
    }
    console.log(arg1); // arg1 = 0
}

zeroCheck(0,2);

Он работал для xdazz, Jeroen Moons и jFriend00 - потому что они не включали строгий: http://jsfiddle.net/nSJGV/ (нестрогий) http://jsfiddle.net/HDjWx/ (строгое)