I've been seeing conflicting information on whether a custom controller is instantiated with a "new" keyword or simply applied to the $scope object.
The documentation site says,
Angular applies (in the sense of JavaScript's Function#apply) the controller constructor function to a new Angular scope object, which sets up an initial scope state. This means that Angular never creates instances of the controller type (by invoking the new operator on the controller constructor). Constructors are always applied to an existing scope object.
But it seems like in Angular 1.2, there is an "as"
construct that will rename a controller to something else as in:
<body ng-controller="DemoController as demo">
<tr ng-repeat="student in demo.students">
<td>{{student.name}}</td>
</tr>
</body>
function DemoController() {
this.students = [...]
}
So this makes it seem like a controller is being instantiated using the new
keyword.
Which one is it? Can someone clarify this?
The "as" syntax is only an alias and the documentation is correct that Angular never creates instances of the controller type by invoking the new operator on the controller constructor. The new behavior with aliasing is such that now $ControllerProvider
does a regexp test for the presence of the as
keyword and, if present, stores a reference to the controller on the local scope under the alias name.
Here is a link to the git feature commit that changed the relevant code.
Also: From the Angular source (1.1.5), here is the code in $ControllerProvider
that creates the controller:
instance = $injector.instantiate(expression, locals);
and here is the instantiate
method:
function instantiate(Type, locals) {
var Constructor = function() {},
instance, returnedValue;
// Check if Type is annotated and use just the given function at n-1 as parameter
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
instance = new Constructor();
returnedValue = invoke(Type, instance, locals);
return isObject(returnedValue) ? returnedValue : instance;
}
So you can see that the new
keyword is indeed invoked but it's invoked on an empty generic function called Constructor
, not the controller constructor. First the prototype of the empty constructor is set to the prototype of the Angular Type
that is passed in to the injector.