#javascript #arrays #recursion
Вопрос:
У меня есть два фрагмента рекурсивного кода, намеревающегося рекурсивно распечатать половину массива, пока мы не доберемся до массивов длиной 1. Код без присвоения переменной выполняется бесконечно, в то время как код с присвоением переменной ведет себя так, как ожидалось.
Есть какие-нибудь зацепки, почему это так?
Бежит бесконечно, ОСТОРОЖНО
function half(arr) {
halfway = Math.floor((arr.length) / 2)
console.log(arr)
if (arr.length > 1) {
half(arr.slice(0, halfway));
half(arr.slice(halfway));
}
return
}
half([1, 2, 3, 4, 5]);
Не работает бесконечно
function half(arr) {
halfway = Math.floor((arr.length) / 2)
console.log(arr)
if (arr.length > 1) {
var a = arr.slice(0, halfway);
var b = arr.slice(halfway);
half(a);
half(b);
}
return
}
half([1, 2, 3, 4, 5]);
Я подумал, что, возможно, здесь может быть задействована какая-то изменчивость, но я не могу представить, как это будет действовать. Я думал, что мы передаем то, что фактически является целым новым массивом, в функцию каждый раз, когда она вызывается…
Комментарии:
1.
var halfway = ...
— В настоящееhalfway
время это глобальная переменная, которая блокируется рекурсивными вызовами.2. Может ли кто-нибудь ответить, почему первый код не выводит [1,2,3,4,5] ?
3. @Тушаршахи, потому что видимые эффекты вызова функции ставятся в очередь, но никогда не получают шанса появиться, потому что бесконечный цикл не заканчивается.
4. @NiettheDarkAbsol, но другие вещи печатаются правильно? И [1,2,3,4,5] должно быть абсолютно первым, что нужно напечатать. Но не делает этого?
Ответ №1:
Потому что ему не хватает var
let
и const
halfway
он имеет глобальный охват, как если бы вы написали window.halfway
. В результате все рекурсивные вызовы изменяют и используют одну и ту же единственную переменную.
В 1-й функции значение изменяется в первом рекурсивном вызове, прежде чем его можно будет использовать во втором рекурсивном вызове. В моем тестировании это фактически привело к своего рода ошибке переполнения стека (или, скорее, ошибке максимального размера стека вызовов), очень подходящей для этого сайта :-).
Во 2-й функции значение используется дважды до начала рекурсивных вызовов, а затем оно изменяется обоими после друг друга.
Проблема решена с помощью const
:
function half1(arr) {
const halfway = Math.floor((arr.length) / 2)
console.log(arr.toString())
if (arr.length > 1) {
half1(arr.slice(0, halfway));
half1(arr.slice(halfway));
}
return
}
function half2(arr) {
const halfway = Math.floor((arr.length) / 2)
console.log(arr.toString())
if (arr.length > 1) {
var a = arr.slice(0, halfway);
var b = arr.slice(halfway);
half2(a);
half2(b);
}
return
}
const data = [1, 2, 3, 4, 5];
half1(data);
console.log("------------------------")
half2(data);
Последнее примечание: вся проблема была бы обнаружена и предотвращена компилятором JS, если бы вы поместили 'use strict';
ее поверх своего кода. Мне не очень нравится, как неуклюже работает эта директива (почему размещение «мертвой и неиспользуемой» строки поверх вашего кода имеет такой особый и далеко идущий эффект?), Но нам придется использовать то, что мы можем получить.