Mwatney
Mwatney

Reputation: 11

Is storing a getElementById outside of functions a good idea?

I think two examples will illustrate my question best.

(function(){
  var myBtn = document.getElementById('myBtn');

  function one() {
      console.log(myBtn.innerHtml);
  }
  function two() {
      myBtn.innerHtml = "apple";
  }
  function three() {
      console.log(myBtn.value);
  }
})();

vs

(function(){
  function one() {
      var myBtn = document.getElementById('myBtn');
      console.log(myBtn.innerHtml);
  }
  function two() {
      var myBtn = document.getElementById('myBtn');
      myBtn.innerHtml = "apple";
  }
  function three() {
      var myBtn = document.getElementById('myBtn');
      console.log(myBtn.value);
  }
})();

So the first examples uses a global variable (or when it's locked withing a self-invoking function it's not a global variable?) the second does not. The first example is more DRY while the second keeps everything within functions.

Which one is better to use? What are the pros and cons of both? Does project scale matter?

Again this is a theoretical example, the functions obviously don't work without html. Thanks.

Upvotes: 1

Views: 602

Answers (5)

potatopeelings
potatopeelings

Reputation: 41065

The reason its recommended that you don't use a global variables is so that you don't pollute the global namespace. The same argument would hold for a large closure. You don't want to be polluting the closure with too many variables

So while something like

(function(){
  var myBtn = document.getElementById('myBtn');

  function one() {
      console.log(myBtn.innerHtml);
  }
  function two() {
      myBtn.innerHtml = "apple";
  }
  function three() {
      console.log(myBtn.value);
  }
})();

does not pollute the global scope, it does pollute the closure i.e. imagine how difficult maintenance would be if you had something like

(function(){
  var myBtn = document.getElementById('myBtn');

  // lots of code..

  function one() {
      console.log(myBtn.innerHtml);
  }

  // lots of code..

  function two() {
      myBtn.innerHtml = "apple";
  }

  // lots of code..

  function three() {
      console.log(myBtn.value);
  }
})();

because you have to know that when you are in three() that myBtn exists in the parent scope and creating a local variable within three would mask that

Another case against using variable from an outer scope

(function(){
  var myBtn = document.getElementById('myBtn');

  // lots of code..

  function one() {
      console.log(myBtn.innerHtml);
  }

  // lots of code..

  var myBtn1 = document.getElementById('myBtn1');

  function two() {
      myBtn1.innerHtml = "apple";
  }

  // lots of code..

  function three() {
      console.log(myBtn.value);
  }
})();

with a long enough outer closure, you'd be forced to keep track of myBtn, myBtn1.... So while this is better than global scope (where you had to keep track of variable across files), now you (just?) have to keep track of all the variables within the closure.

Which begets the question, what would be a better way for large closures. Here is one option

(function () {
    // lots of code..

    function one(myBtn) {
        console.log(myBtn.innerHtml);
    }

    // lots of code..

    function two(myBtn) {
        myBtn.innerHtml = "apple";
    }

    // lots of code..

    function three(myBtn) {
        console.log(myBtn.value);
    }


    var myBtn = document.getElementById('myBtn');

    one(myBtn);
    two(myBtn);
    three(myBtn);
})();

which keeps everything nicely localized. Of course if you have a large closure it is probably an indication that you are doing too much in that closure (module).

Of course for small closures, your first option is pretty ok.

Upvotes: 0

Matías Fidemraizer
Matías Fidemraizer

Reputation: 64923

There's a third and missing approach in your question: using objects.

If myBtn element won't be dropped from the document within the life of the page (i.e. until user refreshes the page F5), as your first approach, you should store a reference to the element in order to avoid querying the document many times:

(function() {

  // SomeObject isn't global, but a local variable of IIFE's scope ;)
  var SomeObject = function() {
    this.myBtn = document.getElementById("myBtn");
  };

  SomeObject.prototype = {
    one: function() {
      console.log(this.myBtn.innerHTML);
    },
    two: function() {
      this.myBtn.innerHtml = "apple";
    },

    three: function() {
      console.log(this.myBtn.value);
    }
  };

  // This is required in order to be sure that SomeObject is going to 
  // be able to retrieve "myBtn" element during its construction time,
  // because the document is already loaded
  document.addEventListener("DOMContentLoaded", function() {
    var some = new SomeObject();
    some.one();
  });
})();
<button id="myBtn">My button</button>

Upvotes: 0

Jacob
Jacob

Reputation: 1004

First one is better to use. it gives cleaner and faster code.

(function(){
  var myBtn = document.getElementById('myBtn');

  function one() {
      console.log(myBtn.innerHtml);
  }
  function two() {
      myBtn.innerHtml = "apple";
  }
  function three() {
      console.log(myBtn.value);
  }
})();

Edit: There is no need to run the same code multiple times when the result would just be stored and shared across all you functions

Upvotes: 0

yzn-pku
yzn-pku

Reputation: 1082

The document.getElementById function will return the reference to the first object with the ID specified. This means it will return the reference to the same object during subsequent calls (in most cases, if used appropriately), which will never refer to other elements, or get invalidated.

You can safely stick to the style of the first example. This is not c++, and your object won't disappear.

Upvotes: 0

Hiltje
Hiltje

Reputation: 140

One of te disadvantages of the second is that within every function the variable needs to be calculated and stored again. This will have an impact on the performance. The variable will be the same in all functions so you could subtract it at place it above the function as in function 1. The variable in example 1 will not become a global variable (because of the use of an iffy). This is also positive. Need to keep the global environment as clean as possible. Personally I think option 1 is also more obvious what is going on.

Upvotes: 1

Related Questions