Menu

Adding clarity to scope inheritance in angular

No matter how old JavaScript gets, the concept of prototypical inheritance still confuses developers. In fact, appendTo just gave a training course on functions and objects that talked about it yesterday! Not to mention Jordan Kasper's great talk on OO JavaScript.

The fact is prototypical inheritance in JavaScript presents confusion to a lot of folks out there. In terms of Angular.js that may explain why the concept of $scope is difficult to grok.

Let's take a step back to the root of the problem and try to understand prototypical inheritance a little better.

POJCF's

If you plan on using the new operator on this Root function, well then it's called a constructor function.

var root = new Root();

Every JavaScript function has a prototype.

When you log the Root.prototype, you get...

Notice a few things here, first of all there's a constructor property on Root.prototype, and a mysterious looking __proto__ member as well.

That proto represents the prototype that this function is based off, and since this is just a plain JavaScript function with no inheritance set up yet, it refers to the Object prototype which is something just built in to JavaScript...

Now then, Child officially "inherits" it's prototype from Root. And there was much rejoicing.

First things first, the Object.createmethod. Don't get to hung up on this, it's job is basically to create a new object based off of whatever you pass in.

In this case what we're doing is setting the prototype of Child to a new object that looks identical to the Root prototype. The next logical step is to reset the Child.prototype.constructor and make sure it still points to the Child function. You have to do this because if you don't, then Child.prototype.constructor would point to the function Root() {}.

Because we set the Child prototype to the Root prototype, the Child.prototype now has the add method available...

Have a look here...

See how you can see the Child has it's .prototype property. Then, the __proto__ helps point to the fact that the prototype of Child is based off of the prototype of Root, and the prototype of Root is based off of Object!

When an ng-controller directive is used, angular will call $rootScope.$new and create a new scope.

Following down the execution path, you'll see that a controller is not going to be an isolate scope so it'll jump into the else block. It then caches a reference to a function called this.$$childScopeClass.

It then sets the prototype of this function to the prototype of Scope...

this.$$childScopeClass.prototype = this;

This is similar to calling Object.create(Scope);, but in this case this is referring to an instance of Scope.

When the controller function fires it's asking for $rootScope and setting rootyThing up on it. Since $scope prototypically inherits from $rootScope you'll see how we're immediately able to access rootyThing on the local controller scope!

The Object.getPrototypeOf($scope); call shows you the controller's $scope prototype is Scope.

Back to the idea of primitives or objects on prototypes, take a look at this...

Then it's also set on the AnotherChildCtrl. Thinking back on the first examples of this, the $scope.name on ChildCtrl has in fact been overwritten in the same way as before.

If you need access to a variable from ChildCtrl inside of AnotherChildCtrl, then you have to use an object to do it! Ain't prototypical inheritance neato.

In general, try not to just assign stuff directly to $scope as primitives. You're $scope is a place to PUT the "model", but is not actually the "model". You'll want to do more with objects and always see a "." in your views when referencing a $scope property.

Conclusion

This stuff seems really complicated when you first get into it. The basic ideas though are all based on prototypical inheritance. If you'll fully grok that, then angular scope inheritance is nothing more than that.