views:

115

answers:

5

Consider the following Javascript function (1):

function setData(domElement) {
  domElement.myDataProperty = {
    'suppose': 'this',
    'object': 'is',
    'static': 'and',
    'pretty': 'big'
  };
};

Now what I don't like about this function is that the exact same object is created every time the function is called. Since the object does not change I would rather create it just once. So we could make the following adjustments (2):

var dataObject = {
  'suppose': 'this',
  'object': 'is',
  'static': 'and',
  'pretty': 'big'
};

function setData(domElement) {
  domElement.myDataProperty = dataObject;
};

Now the object is created once when the script is loaded and stored in dataObject. But let's assume that setData is called only occasionally -- most of the times that the script is loaded the function is not used. What I don't like about this function in that case is that the object is always created and held in memory, including many occasions in which it will never be used. I figured you could do something like this to strike the ideal balance (3):

var dataObject;

function setData(domElement) {
  if (!dataObject) {
    dataObject = {
      'suppose': 'this',
      'object': 'is',
      'static': 'and',
      'pretty': 'big'
    };
  }
  domElement.myDataProperty = dataObject;
};

Would that make sense? I figure it depends on when the interpreter decides to create an object. Does it really wait until it passes the !dataObject condition, or does it enter the function, tries to be smart and decides to construct it in advance? Perhaps different Javascript engines have different policies with regard to this?

Then of course there is the question of whether these optimizations will ever matter in practice. Obviously this depends on factors like the size of the object, the speed of the engine, the amount of resources available, etc.. But in general, which one would you say is the more significant optimization: from (1) to (2) or from (2) to (3)?

A: 

First, I'd implement it in situation #2 and load it once immediately after the page is loaded.

If there was a problem with page speed, I would measure the time taken for specific tasks within the page.

If it was very expensive to create the object (relatively speaking), then I would move to situation #3.

There's no point in adding the 'if' statement if it really doesn't buy you anything... and in this case, creating a simple/big object is no sweat off your CPU's back. Without measurements, you're not optimizing - you're just shooting blind.

It's actually a fairly common method of initializing things that I've personally used in C++ and Java.

Kieveli
A: 

First, this optimization will never matter in practice.

Second, the last function is exactly as good as the first function. Well, almost. In the first I suppose you're at the mercy of the garbage collector, which should destroy the old object when you reassign domElement.myDataProperty. Still, without knowing exactly how the garbage collector works on your target platform (and it can be very different across browsers), you can't be sure you're saving any work at all really.

Triptych
+1  A: 

The answer is, you're not supposed to know. The examples you showed have very little difference between them. The only way you'd ever reasonably worry about this is if you had actual evidence that one way or another was noticably harming performance or memory usage on a particular interpreter. Until then, it's the interpreter's job to worry about that stuff for you.

That said, if you really want to know... Try it and find out. call the different versions 1,000,000 times and see what difference it makes.

Make a giant version of the object and see if that makes a dent. Watch task manager. Try different browsers. Report back your results. It's a much better way to find out than just asking a bunch of jerks on the internet what they guess might be the case.

just keep in mind that object has to be in memory anyway, regardless ... as source text

Breton
+1  A: 

A new object must be created -- it cannot not be, partially because the spec requires it, but mostly because alternative behaviour would be counter intuitive, take:

function f() {
    return {a : "b", c: "d"};
}
o=f();
alert([o.c, o.e]); // Alerts "b,"
delete o.c;
o.e="f";
o=f();
alert([o.c, o.e]); // If the object was only created once this would produce ",f"

Do you really expect a new object expression to not actually produce the object you're asking for? Because that's what you seem to want.

Conceivably you just want to do:

var myFunction = (function(){
    var object = {a: "b", c: "d"};
    return function() { return object; }
})();

Which would get the effect you want, although you would have to realise that the object you're returning is a completely mutable object that can be changed, and everyone would be sharing that same mutating instance.

olliej
Good point, but keep in mind that I'm talking about an object that will never change here, such as a typical function.
Tim Molendijk
doesn't matter, JS says that it can change, the fact the you don't intend to change it is irrelevant. Would you expect 'return [1,2,3];' to always return the same object for instance?
olliej
A: 

Try all three of them in a couple of browsers and find out which is faster.

Nick