Почему this forEach возвращает undefined при использовании оператора return

Object.prototype.e = function() {
    [].forEach.call(this, function(e) {
        return e;
    });
}; 
var w = [1,2];

w.e(); // undefined

Но это работает, если вместо этого я использую alert

// ...
[].forEach.call(this, function(e) {
    alert(e);
});
// ...

w.e(); // 1, 2

Ответ 1

Функция e() ничего не возвращает; внутренняя анонимная функция возвращает значение e, но возвращаемое значение игнорируется вызывающим абонентом (вызывающий function e() (и может ли несколько использования 'e' более запутывать?))

Ответ 2

Я понимаю, что это старый вопрос, но поскольку это первое, что появляется в google при поиске по этой теме, я упомянул, что то, что вы, вероятно, ищете, - это javascript for.. in loop, который ведет себя ближе к каждому из них на многих других языках, таких как С#, С++ и т.д.

for(var x in enumerable) { /*code here*/ }

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/for...in

http://jsfiddle.net/danShumway/e4AUK/1/

Несколько вещей, которые нужно запомнить:

  • for..in не гарантирует, что ваши данные будут возвращены в любом конкретном порядке.
  • Ваша переменная по-прежнему будет ссылаться на индекс, а не на фактическое значение, хранящееся в этом индексе.
  • Также см. ниже комментарии об использовании этого с массивами.

edit: for..in вернет (по крайней мере) добавленные свойства прототипу объекта. Если это нежелательно, вы можете исправить это поведение, добавив свою логику в дополнительную проверку:

for(var x in object) {
    if(object.hasOwnProperty(x)) {
        console.log(x + ": " + object[x]);   
    }
}

Ответ 3

Потому что

function(e) {
    return e;
}

является обратным вызовом. Array.forEach скорее всего называет его таким образом:

function forEach(callback) {
    for(i;i<length;i++) {
        item = arr[i];
        callback.call(context, item, i, etc.)
    }
}

поэтому вызывается обратный вызов, но возврат не идет нигде. Если callback вызывались как:

return callback.call();

он будет возвращать из forEach по первому элементу массива.

Ответ 4

Ваш пример немного странный, но поскольку этот вопрос становится каноническим вопросом "возврат из forEach", попробуйте использовать что-то более простое, чтобы продемонстрировать проблему:

Здесь у нас есть функция, которая проверяет записи в массиве, чтобы увидеть, соответствует ли someProp value, и, если это так, увеличивает значение count в записи и возвращает запись:

function updateAndReturnMatch(array, value) {
    array.forEach(function(entry) {
        if (entry.someProp == value) {
           ++entry.count;
           return entry;
        }
    });
}

Но вызов updateAndReturnMatch дает нам undefined, даже если запись была найдена и обновлена.

Причина в том, что return внутри обратного вызова forEach возвращается из обратного вызова, а не из updateAndReturnMatch. Помните, что обратный вызов является функцией; return в функции возвращается из этой функции, а не той, которая содержит ее.

Чтобы вернуться из updateAndReturnMatch, нам нужно запомнить запись и разбить цикл. Поскольку вы не можете разбить цикл forEach, вместо этого мы будем использовать some:

function updateAndReturnMatch(array, value) {
    var foundEntry;
    array.some(function(entry) {
        if (entry.someProp == value) {
           foundEntry = entry;
           ++foundEntry.count;
           return true; // <== Breaks out of the `some` loop
        }
    });
    return foundEntry;
}

return true возвращается из нашего обратного вызова some, а return foundEntry возвращается из updateAndReturnMatch.

Иногда то, что вы хотите, но часто вышеприведенный шаблон может быть заменен на Array#find, который является новым в ES2015, но может быть настроен для старых браузеров:

function updateAndReturnMatch(array, value) {
    var foundEntry = array.find(function(entry) {
        return entry.someProp == value;
    });
    if (foundEntry) {
        ++foundEntry.count;
    }
    return foundEntry;
}