Safe-guarding AngularJS scopes with ECMAScript 5 "Strict Mode"
Having a history as a Java developer I prefer declaring the complete JavaScript object at once through an object literal; in a similar fashion as your would declare a class in Java. In my opinion adding new properties "on the fly" to a JavaScript object is a very bad practice:
<!-- more -->For the same reasons I dislike how properties are declared in an AngularJS application:
Declaring scopes as object literals
In order to use an object literal to declare your scope one could use the following syntax:
To improve the construction above we could (instead of using angular.extend)
add a declare function to all scope implementations. This can be achieved easily
by adding such a function to the $rootScope:
Now we can rewrite our scope declaration as follows:
Keeping this in scope Using an object literal we can now use this to
refer the scope instance from inside a function declared in the object literal:
The scope declared using the code above contains:
- a property
todoTextwhich is initialized to an empty string - a function
addTodothat will reset thetodoTextproperty to its default value
Now have a look at the following dump of the internal contents of our scope:

In this screenshot (from the Chrome browser) you will notice that:
- Our scope does indeed contain the
todoTextproperty and theaddTodofunction (as well as some other properties / functions omitted from our code sample) - The scope (at this specific moment) is a top-level scope, meaning it isn't contained by any parent scope
- The scope is a direct descendant from the
$rootScope(which always has an$idof "002")
But what if our scope would actually contain a nested TheChildCtrl scope like
this:
This extra TheChildCtrl scope would actually introduce an issue in our
addTodo function. The this, used in the this.todoText = ''; statement, no
longer would refer to the TodoCtrl scope but instead to the TheChildCtrl
scope. To illustrate this have look at following dump to see what the
TheChildCtrl scope and its parent (= TodoCtrl) scope will look like after
the "addTodo()" function was invoked:

The invocation of the addTodo function accidentally introduced a new
todoText property in the TheChildCtrl scope. To prevent this accidental
introduction of properties we will modify our declare function to:
- manually copy the properties from the object literal (instead of using
angular.extend) - explicitly bind each function to the scope instance (using the
angular.bindfunction) to enforce thethisof each scope function:
Now that the "this" in back 'in scope' our "declare" function is fully
functional. To illustrate the benefit of the declare scope syntax I've
rewritten the "Todo" sample from the AngularJS homepage in
a before and
after jsFiddle. Safe-guarding your scopes In
order to ensure that no other properties can be assigned to our $scope than
the properties of our object literal we can enhance our declare function to
returned a "sealed" object instance through return Object.seal(this);. The
Object.seal function is part of EcmaScript 5 and will prevent future
extensions to an object and protects existing properties from being deleted.
However sealing and object isn't enough since by default no errors will be
thrown or logged when the seal is violated. To make object sealing useful we
need to enable the "strict mode" from EcmaScript 5. Enabling it will cause
TypeError's to be thrown when the seal is violated. All modern browser except
Internet Explorer (< IE10) support the usage of "strict mode" To enable strict
mode one needs to add the following 'magic' in front of every ".js" file:
Using object sealing combined with the ECMAScript 5 "strict mode" we can now make a much more advanced implementation of the "declare" function that:
- enforces the actual usage of
$scope.declare; the $scope instance supplied to the controller is of the special extension of the controller $scope of type "UndeclaredScope" which is sealed and only allows invocation of it'sdeclarefunction. - The
declarefunction works in similar fashion as before but now it will also check if the browser actually supports "strict mode"; if this isn't the case (like in Internet Explorer 9 or earlier) it will instead execute to the earlier described "basic" implementation of "declare".
A complete "sealed" + "strict mode" implementation can be found in this jsFiddle.
It includes some commented-out code that all would raise a "TypeError" in case executed inside a "strict mode" browser.