86

I recently tried to create an object like this:

var carousel = {
      $slider: $('#carousel1 .slider'),
      panes: carousel.$slider.children().length
    };

My intentions were to improve jQuery's selector performance by caching the results of $('#carousel1 .slider') in an object property, and to keep the code concise and relatively DRY.

However, this didn't work. When the code executed, it threw an exception when trying to parse the value of panes, complaining that carousel was undefined.

This makes sense, since I'd assume that carousel isn't fully declared until the assignment statement has been fully executed. However, I'd like to avoid resorting to this:

var carousel = {};
carousel.$slider = $('#carousel1 .slider');
carousel.panes = carousel.$slider.children().length;

That's not too much worse, but the carousel object will have several more properties that rely on the values of other properties, so that could quickly become verbose.

I tried using this, but to no avail. I may well not have been using it correctly, or that may not be a valid approach anyway.

Is there a way for properties of an object to refer to other properties of the same object, while that object is still being declared?


Based on Matthew Flaschen and casablanca's answers (thanks, guys!), I think these are the versions of my actual code that I'd end up with, based on each approach:

// Matthew Flaschen

var carousel = new (function() {
  this.$carousel = $('.carousel');
  this.$carousel_window = this.$carousel.find('.window');
  this.$carousel_slider = this.$carousel.find('.slider');
  this.$first_pane = this.$carousel.find('.slider').children(':first-child');
  this.panes = this.$carousel_slider.children().length;
  this.pane_gap = this.$first_pane.css('margin-right');
})();

and

// casablanca

var $carousel = $('.carousel'),
    $carousel_slider = $carousel.find('.slider'),
    $first_pane: $carousel.find('.slider').children(':first-child');

var properties = {
  $carousel_window: $carousel.find('.window'),
  panes: $carousel_slider.children().length,
  pane_gap: $first_pane.css('margin-right')
};

properties.$carousel = $carousel;
properties.$carousel_slider = $carousel_slider;
properties.$first_pane = $first_pane;

Assuming those are both correct (I haven't tested them), it's kind of a tough call. I think I slightly prefer Matthew Flaschen's approach, since the code is contained to a structure that more closely resembles an object declaration. There's also ultimately only one variable created. However, there's a lot of this in there, which seems repetitive - although that may be just the price to pay.

Bungle
  • 19,392
  • 24
  • 79
  • 106
  • 1
    OP: Duplicate isn't necessarily determined chronologically. We try to point everything back to questions with more detailed and extensive answers, with the goal being to point to point to a *canonical* question. However, this is not an easy goal. Marking a question such as this as duplicate isn't a mark against it. Your question will come up on search engines with different terms, and if these answers don't solve the solution, the other (more extensive) question might. – CodeMouse92 Apr 13 '16 at 19:45
  • Case-in-point, I authored what is now considered a canonical question, and many older, narrower-focus questions are being marked as duplicates of it, to funnel site visitors towards the most complete answers. Be proud - your "duplicate" question is helping. :) – CodeMouse92 Apr 13 '16 at 19:46
  • Thanks for clarifying @JasonMc92, that makes sense. Will remove my update. – Bungle Apr 13 '16 at 20:11

2 Answers2

61

Not with object literals (this has the same value during constructing of the literal that it did before-hand). But you can do

var carousel = new (function()
{
      this.$slider =  $('#carousel1 .slider');
      this.panes = this.$slider.children().length;
})();

This uses an object created from an anonymous function constructor.

Note that $slider and panes are public, so can be accessed as carousel.$slider, etc.

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • This is essentially a more verbose version of the OP's second example. – casablanca Jul 04 '10 at 03:25
  • 1
    @casablanca, not really. He asked, "Is there a way for properties of an object to refer to other properties of the same object, while that object is still being declared?", and that's exactly what this is. With my example, `carousel` can use previously defined properties, but it is not accessible from the outside until it's fully constructed. With his code, that wasn't the case. And it *does* use `this` (which the OP said he wanted), rather than having to repeat `carousel`. He said he was planning on adding more properties, which could make this approach shorter too. – Matthew Flaschen Jul 04 '10 at 03:29
  • 1
    I guess you're right about that. – casablanca Jul 04 '10 at 03:44
  • Thanks, Matthew! I actually wasn't entirely set on using `this`, it just seemed like it might have been applicable in this situation. I can't think of a more concise approach than the one you suggested, though, in spite of the numerous references to `this`. I appreciate it. – Bungle Jul 04 '10 at 03:50
  • 1
    @Bungle, you only have use `this` to refer to public properties. For instance, if `$slider` were private, you could replace the first `this.$slider` with `var $slider`, and the second with `$slider`. – Matthew Flaschen Jul 04 '10 at 04:23
  • Thanks, Matthew - that is good to know! In this case, I'm actually intending for all of the properties to be public. – Bungle Jul 04 '10 at 17:31
23

Unfortunately, no. The {} syntax initiates creation of a new object, but until the object is created, it is not assigned to the carousel variable. Also, the this value can only change as a result of a function call. If your "several more properties" are all going to depend only on slider, then you could get around with something like this:

var slider = $('.slider');
var carousel = {
  panes: slider.children.length(),
  something: slider.something_else,
  // ...
};
carousel.slider = slider;
casablanca
  • 69,683
  • 7
  • 133
  • 150
  • Thanks, casablanca! I do like your approach for cases when most of the object properties rely on just one or two other variables. For my use case, unfortunately, that's not the case, so I think Matthew Flaschen's approach ends up being slightly more elegant. Thanks again. – Bungle Jul 04 '10 at 03:48