SitePoint Sponsor

User Tag List

Results 1 to 11 of 11
  1. #1
    SitePoint Zealot
    Join Date
    Aug 2010
    Posts
    193
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    What is the error in this small object?

    When I load this script, FF tells me that on line 4 time: OpenPage.today.getTime(), that OpenPage is undefined. But isn't that object defined when the page loads?

    Code JavaScript:
    var OpenPage = {
     
        today: new Date(),
        time: OpenPage.today.getTime(),
     
        init: function(){
     
            alert(OpenPage.today);
            alert(OpenPage.today.getTime());
     
        }
     
    }
    OpenPage.init();

  2. #2
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,901
    Mentioned
    212 Post(s)
    Tagged
    12 Thread(s)
    Hi,
    This line is causing the trouble:

    Code JavaScript:
    time: OpenPage.today.getTime(),

    AFAIK, there is no way to have values in an object literal's properties depend on other properties declared earlier (today in this case).
    This also accounts for your error message. It is not OpenPage that is undefined, rather OpenPage.today

    To get around this, you could use a getter:

    HTML Code:
    <!DOCTYPE HTML>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>Unbenanntes Dokument</title>
      </head>
      
      <body>
        <script>
          var OpenPage = {
            today: new Date(),
            
            get time(){
              return OpenPage.today.getTime();
            },
            
            init: function(){
              alert(OpenPage.today);
              alert(OpenPage.time);
              alert(OpenPage.today.getTime());
            }
          }
          OpenPage.init();
        </script>
      </body>
    </html>
    More info on getters: https://developer.mozilla.org/en-US/.../Operators/get
    See also: Self-references in object literal declarations

  3. #3
    SitePoint Zealot
    Join Date
    Aug 2010
    Posts
    193
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hey thanks again Pullo!

    seems like such a subtle difference for js to fuss over

    i never saw getter syntax in js before, so just to make sure I'm reading this right, using 'get' space, then a function name i.e. time(), lets me call OpenPage.time as if I declared that property myself??

  4. #4
    SitePoint Zealot
    Join Date
    Aug 2010
    Posts
    193
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    i made a similar error.

    now OpenPage is undefined in footballStart, but i used a getter. but that property works in the alert below


    Code JavaScript:
    var OpenPage = {
     
        today: new Date(),
     
     
     
        get now(){
            return OpenPage.today.getTime();
        },
        get currentYear(){
            return OpenPage.today.getFullYear();
        },
        footballStart: new Date(OpenPage.currentYear,7,9),
     
        init: function(){
     
     
     
            alert(OpenPage.now);
            alert(OpenPage.footballStart);
            alert(OpenPage.currentYear);
     
        },
     
    }
    OpenPage.init();

  5. #5
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,901
    Mentioned
    212 Post(s)
    Tagged
    12 Thread(s)
    Ok, in reverse order:

    You can't do this for the same reason as before:

    Code JavaScript:
    footballStart: new Date(OpenPage.currentYear,7,9)

    it needs to be:

    Code JavaScript:
    get footballStart(){
      return new Date(OpenPage.currentYear,7,9);
    }

    then things will work as expected.

  6. #6
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,901
    Mentioned
    212 Post(s)
    Tagged
    12 Thread(s)
    Quote Originally Posted by sessions View Post
    using 'get' space, then a function name i.e. time(), lets me call OpenPage.time as if I declared that property myself??
    Not quite.

    In your original example, OpenPage's time property referenced OpenPage's today property which was not possible. By using a getter method, you are deferring this referencing until after the object is created.

  7. #7
    SitePoint Zealot
    Join Date
    Aug 2010
    Posts
    193
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    lol, thanks!

    I'll check out that link you posted above.

  8. #8
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,901
    Mentioned
    212 Post(s)
    Tagged
    12 Thread(s)
    Hi,

    I was kind of between doing things when I posted my last answer, so allow me to elaborate, using a simpler example:

    As you know, object literals are comma separated lists of key value pairs wrapped in curly braces.
    Keys can be strings or identifiers, while values can be any valid expression, including array literals, functions, and nested object literals.
    Object literals are used to organise code in a logical fashion and as a means of encapsulating data, so as to avoid polluting the global namespace.

    When creating object literals, you can either first create a blank object, then add properties and methods to it.

    e.g.

    Code JavaScript:
    var object = {};
    object.foo = 1;
    object.bar = null;
    object.baz = function() {
      console.log("hello from baz()");
    };

    or create everything up front, as you were doing in your example:

    Code JavaScript:
    var object = {
      foo : 1,
      bar : null,
      baz : function(){ 
              return "hello from baz()"; 
            }
    };

    Now, the problem you were encountering, is that using the second notation, the object doesn't exist until the whole block is interpreted.
    This means that referencing a previously declared property from within the object, before the object is created, is problematic.

    This works fine:

    Code JavaScript:
    var object = {}
    // object now exists
     
    object.foo = 1;
    object.bar = object.foo + 1;
     
    console.log(object.bar);
    => 2

    This doesn't:

    Code JavaScript:
    var object = {
      foo : 1,
      bar : object.foo + 1
    };
    // object now exists
     
    console.log(object.bar);
    => Uncaught TypeError: Cannot read property 'foo' of undefined

    When you write object.foo + 1, object doesn't exist at this point.

    One way to get around this is to use the aforementioned getter method, thus:

    Code JavaScript:
    var object = {
      foo : 1,
      get bar() { return object.foo + 1 }
    };
     
    console.log(object.bar);
    => 2

    What you are doing here is binding an object property (bar) to a function that will be called when that property is looked up.
    This function will only ever be called after the object exists in memory, so everything works as expected.

    By way of further example and to address your second question, we can add a method to our object like this:

    Code JavaScript:
    var object = {
      foo : 1,
      get bar() { return object.foo + 1 },
      baz : function(){ console.log("hello from baz()"); }
    };
     
    object.baz();
    => hello from baz()

    Now, say we wanted baz() to output the value of bar, then that's no problem as we have a getter in place:

    Code JavaScript:
    var object = {
      foo : 1,
      get bar() { return object.foo + 1 },
      baz : function(){ console.log(object.bar); }
    };
     
    object.baz();
    => 2

    But this getter, doesn't mean that we can use bar from within a property declaration:

    Code JavaScript:
    var object = {
      foo : 1,
      get bar() { return object.foo + 1 },
      foobar : bar + 1
    };
     
    object.foobar();
    => Uncaught ReferenceError: bar is not defined

    Here, you are still trying to access bar before the block has been interpreted and the object exists, which won't work.

    If you want to do this, you have to do the same as before and (for example) use a getter method with foobar

    Code JavaScript:
    var object = {
      foo : 1,
      get bar() { return object.foo + 1 },
      get foobar() { return object.bar + 1}
    };
    console.log(object.foobar);
     
    => 3

    So, I hope that makes a bit more sense.
    I've written more than I had intended, so I'll stop now.

  9. #9
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,688
    Mentioned
    100 Post(s)
    Tagged
    4 Thread(s)
    Since getters don't seem to be supported yet by IE, and since we now understand what is causing the problem, the issue can be easily solved by waiting until the object is defined before adding the time property to it.

    Code:
    var OpenPage = {
        today: new Date(),
        time: OpenPage.today.getTime(),
        init: function(){
            alert(OpenPage.today);
            alert(OpenPage.timetoday.getTime());
        }
    }
    OpenPage.time = OpenPage.today.getTime();
    
    OpenPage.init();
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  10. #10
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,901
    Mentioned
    212 Post(s)
    Tagged
    12 Thread(s)
    Quote Originally Posted by paul_wilkins View Post
    Since getters don't seem to be supported yet by IE
    This isn't quite true.
    According to the docs, this should work in IE9 upwards.
    https://developer.mozilla.org/en-US/..._compatibility

    Quote Originally Posted by paul_wilkins View Post
    since we now understand what is causing the problem, the issue can be easily solved by waiting until the object is defined before adding the time property to it.
    Yup, fair point. This is probably a better way to do things.

  11. #11
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,688
    Mentioned
    100 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by Pullo View Post
    This isn't quite true.
    According to the docs, this should work in IE9 upwards.
    https://developer.mozilla.org/en-US/..._compatibility
    It seems that IE6 is now all-but officially dead. If and when we can stop supporting IE7 and IE8, we can make good use of getters and setters.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •