Having three different methods for defining services is quite confusing for the AngularJS 1.x beginners. Let’s think for a second what necessitated the introduction of these methods for registering services. Why can’t we simply use JavaScript constructor functions, object literals, or ES2015 classes instead, which Angular will not be aware of? We could encapsulate our business logic inside a custom JavaScript constructor function like this:

function UserTransactions(id) {
  this.userId = id;
}
UserTransactions.prototype.makeTransaction = function (amount) {
  // method logic
};

module.controller('MainCtrl', function () {
  this.submitClick = function () {
    new UserTransactions(this.userId).makeTransaction(this.amount);
  };
});

This code is completely valid. However, it doesn’t take advantage of one of the key features that AngularJS 1.x provides—the DI mechanism. The MainCtrl function uses the constructor function, UserTransaction, which is visible in its body. The preceding code has two main pitfalls:

  • We’re coupled with the logic used for the service’s instantiation.
  • The code is not testable. In order to mock UserTransactions, we need to monkey patch it.