Этот реквизит сохраняется неопределенным внутри setInterval [дубликат]

Два трюка . В основном, инвертирование HTML-кода ваших желаемых элементов в HTML и использование ~ Оператора следующего сиблинга :

float-right + инвертирует порядок HTML элементы

div{ /* Do with the parent whatever you know just to make the
  inner float-right elements appear where desired */
  display:inline-block;
}
span{
  float:right;  /* float-right the elements! */
}
span:hover ~ span{ /* On hover target it's "previous";) elements */
  background:red;
} 
<div>
  <!-- Reverse the order of inner elements -->
  <span>5</span>
  <span>4</span>
  <span>3</span>
  <span>2</span>
  <span>1</span>
</div>


Родитель с direction: rtl; + инвертирует порядок внутренних элементов

.inverse{
  direction: rtl;
  display: inline-block; /* inline-block to keep parent at the left of window */
}
span:hover ~ span{ /* On hover target it's "previous";) elements */
  background:gold;
}
Hover one span and see the previous elements being targeted!<br>

<div class="inverse">
  <!-- Reverse the order of inner elements -->
  <span>5</span>
  <span>4</span>
  <span>3</span>
  <span>2</span>
  <span>1</span>
</div>

31
задан Peter Ajtai 27 September 2010 в 02:07
поделиться

5 ответов

Не используйте тайм-ауты. Это эффективный eval, который является Bad Thing. Он работает, потому что он преобразует currentaudio.id и noteTime в строковые представления самих себя и скрывает его в коде. Это работает только до тех пор, пока эти значения имеют toString() s, которые генерируют буквенный синтаксис JavaScript, который воссоздает значение, которое истинно для Number, но не для других.

setTimeout(playNote(currentaudio.id, noteTime), delay);

- это функция вызов. playNote вызывается немедленно, и возвращаемый результат функции (возможно undefined) передается на setTimeout(), а не на то, что вы хотите.

Как упоминаются другие ответы, вы можете использовать встроенное выражение функции с закрытием ссылки currentaudio и noteTime:

setTimeout(function() {
    playNote(currentaudio.id, noteTime);
}, delay);

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

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

setTimeout(function() {
    return function(currentaudio, noteTime) {
        playNote(currentaudio.id, noteTime);
    };
}(currentaudio, noteTime), delay);

, но это становится немного теперь уродливо. Лучше Function#bind, что частично применит для вас функцию:

setTimeout(playNote.bind(window, currentaudio.id, noteTime), delay);

(window для установки значения this внутри функции, что является признаком bind() вам здесь не нужно.)

Однако это функция ECMAScript Fifth Edition, которая еще не поддерживается всеми браузерами. Поэтому, если вы хотите использовать его, вам нужно сначала взломать поддержку, например ::

// Make ECMA262-5 Function#bind work on older browsers
//
if (!('bind' in Function.prototype)) {
    Function.prototype.bind= function(owner) {
        var that= this;
        if (arguments.length<=1) {
            return function() {
                return that.apply(owner, arguments);
            };
        } else {
            var args= Array.prototype.slice.call(arguments, 1);
            return function() {
                return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
            };
        }
    };
}
3
ответ дан bobince 17 August 2018 в 14:26
поделиться

Попробуйте это.

setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay);
7
ответ дан Daniel A. White 17 August 2018 в 14:26
поделиться

Поскольку второй из них вы говорите ему сначала вызвать функцию playNote, а затем передать возвращаемое значение из него в setTimeout.

1
ответ дан dgnorton 17 August 2018 в 14:26
поделиться

Я буквально создал учетную запись на этом сайте, чтобы прокомментировать ответ Питера Айтай (в настоящее время самый высокий голос), только чтобы обнаружить, что вам требуется 50 rep (что бы это ни было), чтобы комментировать, поэтому я сделаю это как ответ, так как это вероятно, стоит отметить пару вещей.

В своем ответе он утверждает следующее:

Вы также можете передать setTimeout ссылку, так как ссылка не выполняется немедленно, но тогда вы не можете передавать аргументы:

setTimeout(playNote, delay);

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

setTimeout(playNote, delay, currentaudio.id, noteTime)

Всегда обращайтесь к документам.

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

Также стоит отметить, что если вы хотите для синтаксического анализа i вашего цикла for в setTimeout(), вам нужно обернуть его в функцию, как описано здесь .

-1
ответ дан Jonathan 17 August 2018 в 14:26
поделиться

Первая форма, которую вы перечислите, работает, так как она будет оценивать строку в конце delay. Использование eval(), как правило, не является хорошей идеей, поэтому вам следует избегать этого.

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

Вместо этого вы должны передать анонимную функцию setTimeout , поэтому правильная форма:

setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay);

Обратите внимание, что вы передаете setTimeout целое функциональное выражение, поэтому он будет удерживать анонимную функцию и выполнять ее только в конце задержки.

Вы также можете передать setTimeout ссылку, так как ссылка не выполняется немедленно, но затем вы не можете передавать аргументы:

setTimeout(playNote, delay);

Примечание:

Для повторных событий вы можете использовать setInterval() , и вы можете установить setInterval() на переменную и использовать переменную, чтобы остановить интервал с помощью clearInterval() .

Вы говорите, что используете setTimeout() в цикле for. Во многих ситуациях лучше использовать setTimeout() в рекурсивной функции. Это связано с тем, что в цикле for переменные, используемые в setTimeout(), не будут такими переменными, какими они были, когда начался setTimeout(), но переменные, как они есть после задержки при запуске функции.

Просто используйте рекурсивную функцию, чтобы обойти эту проблему.

Использование рекурсии для обработки переменных времени задержки:

  // Set original delay
var delay = 500;

  // Call the function for the first time, to begin the recursion.
playNote(xxx, yyy);

  // The recursive function
function playNote(theId, theTime)
{
    // Do whatever has to be done
    // ...

    // Have the function call itself again after a delay, if necessary
    //   you can modify the arguments that you use here. As an
    //   example I add 20 to theTime each time. You can also modify
    //   the delay. I add 1/2 a second to the delay each time as an example.
    //   You can use a condition to continue or stop the recursion

    delay += 500;

    if (condition)
    { setTimeout(function() { playNote(theID, theTime + 20) }, delay); }
}
58
ответ дан Peter Ajtai 17 August 2018 в 14:26
поделиться
  • 1
    Подробное и точное .. +1 – Kranu 27 September 2010 в 03:18
  • 2
    Строго говоря, это не рекурсия, так как функция не вызывает себя непосредственно, она просто ставит в очередь еще один вызов для себя, чтобы выполнить позже. Критически каждый вызов будет возвращен до начала следующего. – Doin 12 May 2016 в 18:17
  • 3
    Большая проблема с вашим "рекурсивным" код состоит в том, что из-за того, что работают замыкания, каждый последующий вызов playNote добавит запись в цепочку замыкания, длина которой будет неограниченно увеличиваться. Подобно бесконечной рекурсии, это BAD IDEA - вы в конечном итоге исчерпаете память! Я отредактировал ответ, чтобы показать, как избежать этого, сохраняя при этом метод в целом. – Doin 12 May 2016 в 18:20
Другие вопросы по тегам:

Похожие вопросы: