A bit about the stuff I've done


Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Wednesday, 24 July 2013

Private members in javascript classes

Whoever told you this couldn't be done was lying.

By utilising closures we can create a class that holds its own private members which cannot be accessed outside of that class - even by adding a new function onto the class

Consider the following javascript function

function Outer() { var PrivateVar='PrivateValue'; function Inner() { PrivateVar='Some Value'; } }

This is known as a closure.
You can read more about them here: http://stackoverflow.com/questions/111102/how-do-javascript-closures-work

Put simply the inner function has access to the variables in the outer function.
These variables are "live" - that is they are not fixed when the inner function was created.

Now consider that the Outer and Inner functions are, in fact, constructors

function MyClassWithPrivateVars(params) { var PrivateVar; function MyClass(params) { PrivateVar='Initial Value'; } return new MyClass(params); } var Instance = new MyClassWithPrivateVars('whatever');

When you call the outer constructor you are actually calling the inner constructor.
The inner constructor has access to the vars within the outer constructor as before.

Let's add a method to the inner constructor.
This new method of course has access to the variables in the outer constructor.

In this instance the method is a "property".

function MyClassWithPrivateVars(params) { var PrivateVar; function MyClass(params) { PrivateVar='Initial Value'; this.PublicProperty = function(value) { if (typeof(value)!=="undefined") { PrivateVar=value; } return PrivateVar; } } return new MyClass(); }

Now if we create an instance of MyClassWithPrivateVars and invoke the property we'll see that it gets the value as expected.

var MyInstance=new MyClassWithPrivateVars(); console.log(MyInstance.PublicProperty());

Outputs "Initial Value" because the private variable was set to that value in the constructor.

MyInstance.PublicProperty(10); console.log(MyInstance.PublicProperty());

This time we get 10

So is the variable really private?

Well - let's try and access it directly:

console.log(MyInstance.PrivateVar);

This should output undefined as PrivateVar is not a member of the inner class.

Likewise

console.log(MyClassWithPrivateVars.PrivateVar);

is also undefined because PrivateVar is a member of the instance of the outer class - not of the constructor itself.

Tuesday, 9 October 2012

The woes of inline functions

OK; so I like inline fucntions really - especially in javascript. But now I am realising their evil intent after I spent a not insubstantial amount of time tracing a bug.
here is the scenario:
A simple method with tbh not a whole lot in it.
In fact the entire method is taken by a single if/else block. Regardless of the outcome of both if blocks it is necassary to call a method afterwards.
So obviously that call goes outside the if.
Normally that would be fine.
But in my case the else block contained an inline function used as a callback.
A callback that will occur some undetermined (but very small) amount of time after the if block has exited.
Of course I needed to wait until this callback had been executed before calling the final method.
function DoSomething() { if (condition) { DoOneThing(); } else { AsyncronuslyDoAnother(function (result){ DoSomethingWithTheResultWhenTheAsyncCallCompletes(); }); } DoFinalThing(); } Now the simple solution in this instance was to move the call to DoFinalThing() to be inside the if block, and also inside the anonymous callback function.
function DoSomething2() { if (condition) { DoOneThing(); DoFinalThing(); } else { AsyncronuslyDoAnother(function (result){ DoSomethingWithTheResultWhenTheAsyncCallCompletes(); DoFinalThing(); }); } } However in my case the problem only arose in the first place because I simply didn't notice the inline function when I added the call to DoFinalThing() and assumed that it was all just part of the else logic.
So additionally I removed the inline function and henceforth declare all such things to be evil!
(ok well not quite, but at least I am more wary now!)
function AsyncCallback(result) { DoSomethingWithTheResultWhenTheAsyncCallCompletes(); DoFinalThing(); } function DoSomething3() { if (condition) { DoOneThing(); DoFinalThing(); } else { AsyncronuslyDoAnother(AsyncCallback); //N.B. no parens on AsyncCallback - we are passing a reference to the method not invoking it } }