3

Can anyone confirm that these samples from Chapter 3 of Pro Javascript Design Patterns are flawed and, if so, how fundamentally - are they more than a typo or two away from producing the intended goal of 'class' constants in JavaScript? Thanks.

var Class = (function() {

  // Constants (created as private static attributes).
  var UPPER_BOUND = 100;

  // Privileged static method.
  this.getUPPER_BOUND() {//sic
    return UPPER_BOUND;
  }

  ...

  // Return the constructor.
  return function(constructorArgument) {
    ...
  }
})();

/* Usage. */

Class.getUPPER_BOUND();

/* Grouping constants together. */

var Class = (function() {

  // Private static attributes.
  var constants = {
    UPPER_BOUND: 100,
    LOWER_BOUND: -100
  }

  // Privileged static method.
  this.getConstant(name) {//sic
    return constants[name];
  }

  ...

  // Return the constructor.
  return function(constructorArgument) {
    ...
  }
})();


/* Usage. */

Class.getConstant('UPPER_BOUND');
Joffer
  • 1,921
  • 2
  • 21
  • 23
  • Javascript isn't classical. Learn to prototype or use another language? read JS: The good parts, instead of what you are reading. – Glenn Ferrie May 27 '11 at 04:49
  • @GlennFerrieLive mostly for the record, I did/do know the prototypical inheritance mechanism, but can see why you assumed otherwise – Joffer Nov 27 '11 at 19:29

6 Answers6

7

I think, this is wrong. As mentioned previously, "this" refers to the window object and the code also has a syntax error. The following code should accomplish the required goal:

var Class = (function () {

    // Private static attributes.

    var constants = {
        UPPER_BOUND: 100,
        LOWER_BOUND: -100
    };            

    var sc = function (constructorArgument) {

    };

    // Privileged static method.
    sc.getConstant = function (name) {
        return constants[name];
    };

    // Return the constructor.
    return sc;
})();

alert(Class.getConstant('UPPER_BOUND'));
Cosmin
  • 21,216
  • 5
  • 45
  • 60
Aman Mahajan
  • 161
  • 1
  • 2
  • This is what the book was looking to show by having a privileged static method, but went quite wrong with their example. Thanx for this. – Zaptree Aug 17 '12 at 03:50
1

Check this out as a good alternative: http://www.klauskomenda.com/code/javascript-programming-patterns/

and for immutable public properties, as was suggested, use Object.freeze and John Resig's great advice: http://ejohn.org/blog/ecmascript-5-objects-and-properties/

and for a way to not clobber your global scope, add namespaces to jQuery: Is it possible to create a namespace in jQuery?

Community
  • 1
  • 1
Milimetric
  • 13,411
  • 4
  • 44
  • 56
  • Yeah, in general I haven't read a book in like 7 years. I know there are some good ones, but I get everything I need online. – Milimetric May 26 '11 at 12:57
  • Thanks for the link. I think the Revealing Module pattern will be useful for enumerations and singletons. Forgive me if I'm wrong, but I don't think that any of the patterns presented could be used to give a class public immutable fields if instantiation of that class is to be unrestricted, which is the intent of the pattern transcribed in my question. Do you know of any patterns that successfully implement this intent? I'm thinking of using Object.freeze(obj.prototype) in conjunction with the formulation demonstrated under the Custom Object header in your link. – Joffer May 27 '11 at 02:37
  • 1
    You're right, that article doesn't talk about immutable public properties. I think that concept wasn't around when it was written. Object.freeze does indeed do that, check out John Resig's great post on it: http://ejohn.org/blog/ecmascript-5-objects-and-properties/. Note that this would require more advanced javascript support. – Milimetric May 27 '11 at 04:44
  • That's kind of a separate consideration. I've adapted it by adding a simple namespaces plugin (http://stackoverflow.com/questions/527089/is-it-possible-to-create-a-namespace-in-jquery) to jQuery so I can do stuff like: `jQuery.myNamespace.safeFromGlobalScopeStuffHere`. I still think the principles outlined in the klauskomenda article I posted are very sound. – Milimetric Dec 05 '11 at 03:18
  • @Milimetric did you read RobG's answer. the code isn't even valid in terms of syntax. Also namespaces are a tool for _module loading_ not _module writing_ – Raynos Dec 05 '11 at 03:24
  • @Raynos, yes, I read RobG's answer, I'm not sure what the code in the book has to do with my post or my comments. Namespace is just a word, I agree with you on its connotation but I think its denotation allows us to use it as I've outlined. – Milimetric Dec 05 '11 at 15:04
  • @Raynos, are you by any chance commenting on the wrong answer? :) – Milimetric Dec 05 '11 at 15:06
  • @Milimetric My main objection is that the phrase "this is ok" implies the code is ok, when it's clearly not because it wont even run without an error. The namespacing technique itself is just a modular code technique and is indeed ok. – Raynos Dec 05 '11 at 15:08
  • oh, lol, I mis-typed then. I meant THIS as in, my answer. I will edit. – Milimetric Dec 05 '11 at 15:28
1

Be wary of anything claiming to be "Pro" whatever. I haven't read the book, but my take on the code is as follows:

> var Class = (function() {
> 
>   // Constants (created as private static attributes).

The word "attributes" is wrong, it should be either "properties" or "variables" because they are variables, which can also be described as properties of the local activation/variable object.

>   var UPPER_BOUND = 100;
> 
>   // Privileged static method.  
>   this.getUPPER_BOUND() {//sic

The code will be executed in a global context where this is the window/global object. So if there is a global *getUPPER_BOUND* function, it will be called with no arguments. It is followed by a curly brace ({) which opens a block in a place where a block can't be, so that is a syntax error.

I presume the following was intended:

    this.getUPPER_BOUND = function() {

which creates a getUPPER_BOUND property of the global/window object that is assiged the anonymous function on the RHS when the code is run.

>     return UPPER_BOUND;   }
> 
>   ...
> 
>   // Return the constructor.
>   return function(constructorArgument) {

This is the function that is assigned to the global variable "Class".

>     ... 
>   }
>  })();

With fixes it may "work", but not elegantly. Any book with such glaring errors in the code has not been carefully written and certainly hasn't been properly reviewed before being published.

Use reputable online resources and continue to ask questions about anything you don't understand or think is in error. There are other forums for discussing javascript that can provide far more detailed answers for technical questions.

RobG
  • 142,382
  • 31
  • 172
  • 209
1

The code can be trivially fixed as

var Class = {
  UPPER_BOUND: 100
};

The rest of the code is over engineered or plain wrong and should be ignored.

If you care about being read only then set the writable flag to false (note the default is false).

var Class = {};
Object.defineProperty(Class, "UPPER_BOUND", {
  value: 100,
  enumerable: true,
  configurable: true
});
Raynos
  • 166,823
  • 56
  • 351
  • 396
  • my problem here is that UPPER_BOUND is mutable and therefore not constant – Joffer Jan 17 '12 at 00:07
  • I would leave configurable as false too, but yeah that works - thanks. I guess the book predates Object.defineProperty – Joffer Jan 17 '12 at 01:02
  • @Joffer always leave configurable as true. They day you try to monkey patch or extend a class/library/3rd-party thing and you realise you can't overwrite or remove a property is the day you curse that library for being so damned inflexible. – Raynos Jan 17 '12 at 01:12
0

Got this to work, but not sure if this was what the authors intended it to be.

var Class = (function()
{
    // Constants (created as private static attributes).
    var constants =
    {
        UPPER_BOUND: 100,
        LOWER_BOUND: -100
    };

    // Return the method(s).
    return {
        getConstant: function(name)
        {
            return constants[name];
        }
    }
}());

console.log(Class.getConstant('UPPER_BOUND')); // shows "100" in console
Jon Saw
  • 7,599
  • 6
  • 48
  • 57
  • your solution avoids the problem of getConstant being made a property of window but we still have to instantiate the class. – Joffer Nov 27 '11 at 19:31
  • How about this? Returned the methods directly instead. This way, we do not have to initiate the Class first. – Jon Saw Dec 04 '11 at 23:35
  • problem now is that we can't instantiate the class – Joffer Feb 01 '12 at 00:03
0

How about do it this way?

/* Grouping constants together. */
var Class = (function() {
  // Private static attributes.
  var constants = {
     UPPER_BOUND: 100,
     LOWER_BOUND: -100
  }

  // Return the constructor.
  return new function(constructorArgument) {
     // Privileged static method.
     this.getConstant = function(name) {//sic
       return constants[name];
     }
   }
})();

console.log(Class.getConstant("LOWER_BOUND"));
bensiu
  • 24,660
  • 56
  • 77
  • 117
pinocchio
  • 71
  • 7