Question

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?

Était-ce utile?

La solution

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top