2014-01-16 4 views
0

Вот тест, который я пытаюсь передать:Почему «возврат» не прерывает мой цикл?

describe("occur", function() { 
    var getVal = function(i) { return i; }; 
    var even = function(num) { return num % 2 === 0; }; 

    it("should handle an empty set", function() { 
    expect(occur([], getVal)).toEqual(true); 
    }); 

    it("should handle a set that contains only true values", function() { 
    expect(occur([true, true, false], getVal)).toEqual(false); 
    }); 

    it("should handle a set that contains one false value", function() { 
    expect(occur([true, true, true], getVal)).toEqual(true); 
    }); 

    it("should handle a set that contains even numbers", function() { 
    expect(occur([0, 8, 32], even)).toEqual(true); 
    }); 

    it("should handle a set that contains an odd number", function() { 
    expect(occur([0, 13, 68], even)).toEqual(false); 
    }); 
}); 

Вот мой код:

var forEach = function(array, action){ 
    for (var i = 0; i < array.length; i ++){ 
    action(array[i]); 
    } 
}; 

var occur = function(array, blah){ 
    forEach(array, function(el){ 
    if(!blah(el)){ 
     return false; 
    } 
    }); 
    return true; 
}; 

То, что я считаю, что я делаю в моей происходят функции:

  1. Взятие параметров (массив и функция
  2. Итерация по массиву (в поле для каждого)
  3. Если blah (el) неверно, верните false (не должно ли это прерывать цикл и возвращать false, когда функция, переданная в значение false, принимает значение false?
  4. return true, если нет никаких ложных значений
  5. ** В настоящее время я не имею случай для пустого массива.

Я пропустил трюк с тем, как работает возврат? Я предоставил ее repl.it сессии ниже (ссылка). Я включил console.log внутри оператора if, и он регистрирует ложь, когда значение ложно, но возвращаемое значение все равно не выводит или не прерывает цикл.

http://repl.it/NjH/1

+2

возвращение * только когда-либо * возвращается из * ближайшей функции ограждающей *. То есть обратный вызов 'forEach' в указанном выше коде. (Функция 'forEach' не возвращает ничего полезного, я бы создал' any/some' или 'filter' - оба из которых существуют в ES5/5.1 - вместо этого и использовать возвращаемое значение.) – user2864740

+0

Я думаю, что один из мои проблемы с моим пониманием не полностью обертывают мою голову вокруг функций «обратного вызова». Я не слишком уверен, что вы подразумеваете под «ближайшей закрывающей функцией». Как определяется «ближайший»? – HelloWorld

ответ

1

Основная проблемы является то, что returnвсегда выходит из ближайшей функции ограждающей -. и никто другие.

var occur = function(array, blah){ // <-- "outer" function 
    forEach(array, function(el){ // <-- callback to forEach/"enclosing" function 
    if(!blah(el)){ 
     // This returns from the callback/enclosing function; it has no 
     // bearing on the outer function. 
     return false; 
    } 
    }); 
    return true; 
}; 

Запрет на смену подходов, эта проблема может быть решена с использованием переменной.

var occur = function(array, blah){ 
    var ret = true; 
    forEach(array, function(el){ 
    if(!blah(el)){ 
     // Set the closed-over variable to false, so that when the return 
     // in the outer function is reached the correct value will be returned. 
     // (forEach will still iterate over every remaining item) 
     ret = false; 
    } 
    }); 
    return ret; 
}; 

Теперь моя рекомендация состоит в том, чтобы использовать что-то вроде Array.some (который находится в ES5.1 и поддерживается в IE9 +, и каждый современный браузер записки).

var occur = function(array, blah){ 
    var any = array.some(function(el){ 
    if(!blah(el)){ 
     return true; 
    } 
    }); 
    return !any; 
}; 

Но на самом деле, изменение условий (отрицания внутри/снаружи и some к every):

var occur = function(array, blah){ 
    return array.every(function(el){ 
    return blah(el); 
    }); 
}; 
1

forEach не возвращает значение в Javascript--, когда вы вернетесь false, вы просто возвращаются false от обратного вызова forEach «s. Значение игнорируется.

Вместо этого, вы можете попробовать Array.every(), если вы используете совместимую реализацию как Node/Webkit/что-то, что поддерживает ECMAScript 5.

В противном случае, установите переменную семафора вне forEach, и установить его на ложь, если blah(el) возвращает false. Затем проверьте значение переменной после завершения forEach.

1

Вам не пропавших без вести трюк с кодом return, вам не хватает одного примерно .forEach.

Для каждого в основном выглядит следующим образом:

function forEach (action) { 
    var arr = this, 
     i = 0, l = arr.length; 

    for (; i < l; i += 1) { 
     action(arr[i], i, arr); 
    } 
} 

Там больше, чем просто, но на самом деле, это то, что он делает.

Так что если action() имеет return заявление, в нем (и даже если это не так, он просто возвращает undefined, это не имеет значения для контура на всех.

Он говорит «Foreach» и что это получите вас один проход через каждый элемент в массиве (который существует в момент вызова функции)

+1

@ user2864740 Он не исправляет проблему с возвратом. Это подчеркивает проблему с возвратом, отвечая на вопрос: «Мне не хватает трюка с тем, как работает возврат», поскольку это дословно наивная реализация «.forEach», чтобы показать, в чем заключается проблема, научиться ловить рыбу, а не поймать его. Более длинный ответ, добавленный к этому, может прийти позже. – Norguard

+1

@ user2864740 Bah. Вы правы - моя неудача заключалась в том, что вы не заметили, что это был не собственный «Array.prototype». forEach', и поэтому я упускал из виду природу непонимания. Использование '[] .forEach' без понимания отношения цикла/обратного вызова не является проблемой. Мои извинения; Я обновлю этот ответ во время моего следующего умственного разрыва. – Norguard

Смежные вопросы