Optimizing code using Object.defineProperty instead of $scope for $watch in AngularJs

It is all about performance

No long ago I wrote an article about “KnockoutJs computed equivalent in AngularJs”. In that article I pointed that the Angular equivalent of a KnockoutJs computer is the $scope.$watch() service. angularjs performance defineProperty

With the pass of the time, I discovered that using $watch in angular can affect the performance of the application, so I was wondering if there is an alternative to $watch to improve the performance of an application specially if it is a large application…

The answer is yes, there is an alternative to $watch.
Note:
It is using Object.defineProperty(), when you planning to use defineProperty, you have to keep in maind that it is supported only by Internet Explorer 9 and above.

First thing first:

To achieve this we will need to use the “controller As” syntax instead of injecting the $scope.
Although The “Controller As” syntax is basically your controller published to the $scope (this syntax is supported by Angular 1.2 and above), here are some reasons to use the “Controller As” syntax over the $scope syntax:

(from John Papa Angular style guide):

Use the controllerAs syntax over the classic controller with $scope syntax.

Why?: Controllers are constructed, “newed” up, and provide a single new instance, and the controllerAs syntax is closer to that of a JavaScript constructor than the classic $scope syntax.

Why?: It promotes the use of binding to a “dotted” object in the View (e.g. customer.name instead of name), which is more contextual, easier to read, and avoids any reference issues that may occur without “dotting”.

Why?: Helps avoid using $parent calls in Views with nested controllers.

<!-- avoid -->


<div ng-controller="Customer">
    {{ name }}
</div>


<!-- recommended -->


<div ng-controller="Customer as customer">
    {{ customer.name }}
</div>


 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

Using defineProperty instead of the angular $watch service, to watch a property.

In general, when we going to need to use a $watch?
A: Whenever we need to subscribe to and object and observe when the value change and trigger an action as a response to that change.

Advise: In general, using $watch in controllers is something to be avoided whenever possible.

Here is a simple example of how to implement defineProperty:

Object.defineProperty(myController.prototype,
    'controllerPropertyName', {
    get: function () {
        return this._personName;
    },
    set: function (newValue) {
        this._personName = newValue;
        //Call method on update here
    },
    enumerable: true,
    configurable: true
});
}

To make this works in angular we will need to wrap the defineProperty within a service:

var myApp = angular.module('myApp', []);
myApp.service('efficientWatch', efficientWatch);

function efficientWatch() {
    this.watch = function (name, controllerProto, func) {
        Object.defineProperty(controllerProto,
        name, {
            get: function () {

                return this._personName;
            },
            set: function (newValue) {
                this._personName = newValue;

                //Call method on update
                if (typeof func == 'function') func(newValue);

            },
            enumerable: true,
            configurable: true
        });
    };
};

You can see the code working together here.
http://jsfiddle.net/ks5et82p/176/