Почему эта неправильная программа JavaScript дает правильный ответ? - PullRequest
4 голосов
/ 12 марта 2020

Мне дали следующую JavaScript программу в интервью.

const average = xs => {
    let sum = 0;
    for (let num in xs) sum += num;
    return sum / xs.length;
};

const result = average([2, 4, 6]);

console.log(result); // 4

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

В приведенном выше коде есть ошибка. Тем не менее, он дает правильный ответ. Можете ли вы найти ошибку и исправить ее? Кроме того, можете ли вы объяснить, почему приведенный выше код дает правильный ответ, даже если он неправильный?

Ответы [ 2 ]

6 голосов
/ 12 марта 2020

Проблема в том, что вы используете for...in l oop вместо for...of l oop. A for...of l oop будет перебирать элементы массива и давать правильный ответ независимо от ввода. Однако for...in l oop перебирает индексы массива. Следовательно, это даст неправильный ответ в большинстве случаев. Тем не менее, для этого конкретного ввода он дает правильный ответ.

|  sum   | num |
| ------ | --- |
|  0     | "0" |
| "00"   | "1" |
| "001"  | "2" |
| "0012" |     |

Индексы массива: "0", "1" и "2". Индексы - это строки, а не числа. Следовательно, когда вы добавляете индекс "0" к начальному значению sum, то есть 0, тогда JavaScript преобразует sum в строку, объединяет две строки и сохраняет объединенную строку обратно в sum. В конце l oop значение sum равно "0012" вместо ожидаемого значения 12.

Однако оба значения "0012" / 3 и 12 / 3 дают правильный ответ, т.е. 4. В первом случае JavaScript сначала преобразует строку "0012" в число 12. Следовательно, мы случайно получаем правильный ответ для этого конкретного ввода.

0 голосов
/ 12 марта 2020

для ... используется для получения ключей в объекте. Поскольку массив является специальной реализацией объекта, имеющего ключи в качестве числовых индексов , for ... in возвращает эти ключи.

keys как '0', '1', '2'

После каждой итерации происходит конкатенация строк"0" + "0" + "1" + "2" sum = "0012"

При попытке деления это неявно преобразуется в число 12/3=4

Таким образом, вывод получается как 4.

Это можно увидеть в следующем фрагменте кода

let xs = [2,4,6], sum=0 
for (let num in xs) { sum += num; console.log(num,sum); }
...