Hoisting is only part of the story here.
First, to explain hoisting:
When you use var in a JavaScript program, you declare a variable. Wherever that variable is declared in a JS scope, it is hoisted to the top of that scope. JavaScript has only Global or Function scope; in the case of a function
function hoistAway() {
  console.log(a);
  var a = 5;
}
is equivalent to
function hoistAway() {
  var a;
  console.log(a);
  a = 5;
}
As you can see, the declaration is hoisted, but the initialization is not. Thus, this code would log undefined on the console, rather than 5. However, it would be satisfied that a exists.
When you don't use var, the declaration is not explicit, so it doesn't get hoisted. Thus:
function hoistAway() {
  console.log(a);
  a = 5;
}
will result in an error message.
In your examples:
window.Foo = Foo;
Foo was never declared, so you get an error.
window.Foo = Foo;
Foo = function() {
    ...
};
Again, Foo was not declared, so no hoisting. For the record:
window.Foo = Foo;
var Foo = function() {
    ...
};
will not throw an error. However, only the declaration is hoisted, so if you did something like
var bob = {};
bob.Foo = Foo;
var Foo = function() {
    ...
};
then bob.Foo would be undefined. The special case of window.Foo = Foo is weird because Foo and window.Foo are the same in the Global scope.
Finally:
window.Foo = Foo;
function Foo(){
    ...
};
works, because function declarations (as opposed to function expressions) are also hoisted; both the name and the definition gets hoisted, so this would work as intended.