Debugging into angular's source code, whenever angular compiles an element having ng-controller
, it calls this function to instantiate the controller and injects all dependencies:
controllerInstance = $controller(controller, locals);
Inside the $controller
method, it calls this method
instance = $injector.instantiate(expression, locals);
to instantiate the controller based on the expression, in your case is function ($injector,$scope){}
:
Which in turn calls invoke
, notice this code snippet:
for(i = 0, length = $inject.length; i < length; i++) {
key = $inject[i];
if (typeof key !== 'string') {
throw $injectorMinErr('itkn',
'Incorrect injection token! Expected service name as string, got {0}', key);
}
args.push(
locals && locals.hasOwnProperty(key)
? locals[key]
: getService(key)
);
}
This loop is to create all dependencies and store in the args
array. For each loop, it checks for locals
first (containing something like $scope
,$element
,$attr
for the current element). The important function call to notice is the getService(key)
:
function getService(serviceName) {
if (cache.hasOwnProperty(serviceName)) {
if (cache[serviceName] === INSTANTIATING) {
throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- '));
}
return cache[serviceName]; //angular run to this line for $injector service
} else {
try {
path.unshift(serviceName);
cache[serviceName] = INSTANTIATING;
return cache[serviceName] = factory(serviceName);
} catch (err) {
if (cache[serviceName] === INSTANTIATING) {
delete cache[serviceName];
}
throw err;
} finally {
path.shift();
}
}
}
In case of $injector
service, when angular initializes the module, it creates an $injector
and store in this cache
.
This means that $injector
does not inject itself, $injector
is just another service in this service cache
. Whenever angular needs to inject a service, angular will look in this cache
, if the service does not exist, angular will create it. $injector
is one of the first services in this cache