Yep! What you're missing is that food is a map. There's only one map in your code, and it lives on the Animal object. When you write gorilla.food, you're accessing that map on Animal, because it has not been overridden on gorilla. Same for zebra, which also has not overridden food. So in the end, Animal.food, gorilla.food, and zebra.food are just three different ways to reference the same map.
Note that this is true for name as well. You didn't override name in zebra, so zebra.name is just another way to access Animal.name. But you don't notice anything odd about this, because strings are immutable; you can't change a string (you can only replace it with a different string).
But maps are mutable. So, if you change a value within the map, you will see that change no matter how you access it.
The solution is to do like you did with name: assign a different map to the instances, rather than just mutate the map that's already on the base class. In fact it might be better to use Animal.food = null in your class, to remind you that each instance needs to get its own food map. Often this is done in some kind of factory function, like this:
Animal = {}
Animal.name = "unknown"
Animal.Make = function
noob = new self
noob.food = {}
return noob
end function
gorilla = Animal.Make
gorilla.food["Banana"] = "twice a day"
gorilla.food["Nuts"]="100g."
zebra = Animal.Make
print zebra.food // prints empty {}
print zebra.name // "unknown", as expected
Let me know if you have any questions!