This is what helped me to understand the difference, thanks to a blog post by Pascal Precht.
A service is a method on a module that takes a name and a function that defines the service. You can inject and use that particular service in other components, like controllers, directives and filters. A factory is a method on a module and it also takes a name and a function, that defines the factory. We can also inject and use the it same way we did with the service.
Objects created with new use the value of the prototype property of their constructor function as their prototype, so I found the Angular code that calls Object.create(), that I believe is the service constructor function when it gets instantiated. However, a factory function is really just a function that gets called, which is why we have to return an object literal for the factory.
Here is the angular 1.5 code I found for factory:
var needsRecurse = false;
var destination = copyType(source);
if (destination === undefined) {
destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
needsRecurse = true;
}
Angular source code snippet for the factory() function:
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
}
It takes the name and the factory function that is passed and returns a provider with the same name, that has a $get method which is our factory function. Whenever you ask the injector for a specific dependency, it basically asks the corresponding provider for an instance of that service, by calling the $get() method. That’s why $get() is required, when creating providers.
Here is the angular 1.5 code for service.
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
It turns out that when we call service(), it actually calls factory()! However, it doesn’t just pass our service constructor function to the factory as is. It also passes a function that asks the injector to instantiate an object by the given constructor.
In other words, if we inject MyService somewhere, what happens in the code is:
MyServiceProvider.$get(); // return the instance of the service
To restate it again, a service calls a factory, which is a $get() method on the corresponding provider. Moreover, $injector.instantiate() is the method that ultimately calls Object.create() with the constructor function. That’s why we use "this" in services.
For ES5 it doesn't matter which we use: service() or factory(), it’s always a factory that is called which creates a provider for our service.
You can do the exact same thing with services as well though. A service is a constructor function, however, that doesn’t prevent us from returning object literals. So we can take our service code and write it in a way that it basically does the exact same thing as our factory or in other words, you can write a service as a factory to return an object.
Why do most people recommend to use factories over services? This is the best answer I've seen which comes from Pawel Kozlowski's book: Mastering Web Application Development with AngularJS.
The factory method is the most common way of getting objects into
AngularJS dependency injection system. It is very flexible and can
contain sophisticated creation logic. Since factories are regular
functions, we can also take advantage of a new lexical scope to
simulate "private" variables. This is very useful as we can hide
implementation details of a given service."