4

This bit of code is from this answer.

I'm trying to understand how it works but I'm not getting it all.

What I think is happening is TEST_ERROR is a closure so ErrorValue can't be changed. One would reference a value like this: TEST_ERROR.SUCCESS. Please correct me if either of those statements are incorrect.

What I don't understand is what the return statement is doing. It's returning an object made up of different ErrorValues, but returning it to what? And what is it returning from? And when is it being called?

var TEST_ERROR = (function() {
  function ErrorValue(value, friendly) {
    this.value = value;
    this.friendly = friendly;
  }
  ErrorValue.prototype = {
    toString: function() { return this.friendly; },
    valueOf: function() { return this.value; }
  };
  return {
    'SUCCESS': new ErrorValue(0, 'Success'),
    'FAIL': new ErrorValue(1, 'Fail'),
    'ID_ERROR': new ErrorValue(2, 'ID error')
  };
})(); 

Thanks!

Paul

Community
  • 1
  • 1
Paul
  • 19,704
  • 14
  • 78
  • 96
  • The function is enclosed by parenthesis that are executed. Something like `(function() { alert('Hello'); })();`. The return value (the `{}`) is assigned to `TEST_ERROR`. – joksnet Dec 21 '10 at 21:04

6 Answers6

6

TEST_ERROR is a closure so ErrorValue can't be changed.

TEST_ERROR will end up just being the object specified in the return statement inside the anonymous function. This object can be changed.

One would reference a value like this: TEST_ERROR.SUCCESS

That's correct.

What I don't understand is what the return statement is doing. It's returning an object made up of different ErrorValues, but returning it to what? And what is it returning from? And when is it being called?

The return statement is returning from the anonymous function that's declared with

(function() { ...})();

The () at the end means that the anonymous function is being called immediately after it is declared, and the value inside the return block is assigned to TEST_ERROR

Here's a good article on closures and emulating private variables that might be useful.

Community
  • 1
  • 1
Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307
  • The ErrorValue objects can still be changed. Change your answer. – Rudie Dec 21 '10 at 21:10
  • @Rudie: I never say the ErrorValue object cannot be changed. Updated the answer though. – Andrew Whitaker Dec 21 '10 at 21:11
  • I can change both TEST_ERROR and its ErrorValues then? Let me see if I get this - TEST_ERROR is an object containing ErrorValue objects as properties. I could also put a function in TEST_ERROR too, right? For example, if I wanted to check if a value was a valid value of TEST_ERROR I could write a function TEST_ERROR.isValid(myVal) and do something like: for (var v in TEST_ERROR) and then compare myVal to each v. Thank you for the link - this is starting to sink in though my brain is complaining...it's tricky stuff! – Paul Dec 21 '10 at 21:46
  • @Paul: Yep, you could add a function--You would have to return a reference to it in the returned object--something like `return { isValid: function() { ... } }`. If you're looking for more resources on JavaScript and scoping/closure, JavaScript: The Definitive Guide is a great reference: http://www.amazon.com/JavaScript-Definitive-Guide-David-Flanagan/dp/0596101996/ref=sr_1_1?ie=UTF8&qid=1292968898&sr=8-1 – Andrew Whitaker Dec 21 '10 at 22:02
2

It is returning its result to TEST_ERROR

var TEST_ERROR = 

and it is being called immediately:

})();

This is a common javascript pattern. You create an anonymous function just for the privacy/scoping it provides, then execute it immediately rather than keeping it around.

Gabe Moothart
  • 31,211
  • 14
  • 77
  • 99
1

This code creates a class called TEST_ERROR. The function ErrorValue is the constructor of the class which defines two attributes: value and friendly. The class has two functions: toString (which returns friendly for any given instance) and valueOf (which returns the value for any given instance). Finally this class declares three class-level attributes (SUCESS, FAIL and ID_ERROR) that can be accessed without an instance of that class (kind of like C#'s static members).

Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
0
var TEST_ERROR = ( // these parenthesis evaluate the function expression

function() { // anonymous function
  function ErrorValue(value, friendly) {
    this.value = value;
    this.friendly = friendly;
  }
  ErrorValue.prototype = {
    toString: function() { return this.friendly; },
    valueOf: function() { return this.value; }
  };

  // return an object from the function
  return {
    'SUCCESS': new ErrorValue(0, 'Success'),
    'FAIL': new ErrorValue(1, 'Fail'),
    'ID_ERROR': new ErrorValue(2, 'ID error')
  };
}
) 
(); // call the evaluated function which returns the "enum" object and assign
    // that value to TEST_ERROR

So yes TEST_ERROR will have be {SUCCESS: ..., FAIL: ..., ID_ERROR: ...} and you can't mess with the values them selfs since you have not access to ErrorValue.

Ivo Wetzel
  • 46,459
  • 16
  • 98
  • 112
  • Thanks for your answer. What keeps value and friendly from being referenced like in Rudie's answer? – Paul Dec 21 '10 at 21:42
  • Scratch that, I'm tired, of course they can be referenced and changed changed. You need to use `var value` / `var friendly` inside `ErrorValue` and then define `this.toString = ...` and `this.valueOf = ` inside there to, then the values can't be changed from the outside. – Ivo Wetzel Dec 21 '10 at 21:48
0

Yes it is essentially returning an Object with three members SUCCESS, FAIL, ID_ERROR, each one representing an ErrorValue. In javascript we can access the members through dot notation or via indexer.

ErrorValue cannot be instantiated outside of the object because it's scope is limited...

akaphenom
  • 6,728
  • 10
  • 59
  • 109
0

I'm pretty (very) sure you can still change the values:

TEST_ERROR.FAIL.value = 7;
Rudie
  • 52,220
  • 42
  • 131
  • 173