Search code examples
javascriptconstructorprototype

Accessing variables in a constructor function using a prototype methode


Why can't i access the variable HTML in the constructor function using the prototype method .nextSlide?

function test(root){

    var HTML = getAllHTML();

    function getAllHTML(){

        var boss, expoHTML;
        var boss = document.querySelector(root);

        expoHTML = {

            slides: boss.querySelectorAll(".slide"),
            prev: boss.querySelector(".control.prev"),
            next: boss.querySelector(".control.next"),
            current: boss.querySelector(".slide-current"),
            total: boss.querySelector(".slide-total")

        }

        return expoHTML;

    }


}


EXPOjs.prototype.nextSlide = function(){

    alert(HTML.current)

}


var newTEST = new test(".ieps");
newTEST.nextSlide();

Solution

  • It's a "scope" problem; every variable in Javascript has a scope, which means: "who can see this variable"?

    In your case, HTML is defined in the function test(). This means that it will be visible:

    • Within the function test()
    • Within any functions defined within test()

    That's it. Outside test(), HTML will be empty.

    Now, I can see that you are using test() as a constructor function. With this, you enter the wonderful world of object creation and Javacript. Take a deep breath :D

    When you do this:

    function Person( age ){
      this.age = age;
    }
    

    And then you do:

    var pavlo = new Person( 23 );
    

    Basically "new" has the effect of:

    • Creating an empty object
    • Running your function so that this points to the newly created object
    • Assign the newly created object to pavlo

    This trickery means that you can do

    var pavlo = new Person( 23);
    console.log( pavlo.age );
    

    And then there are prototype functions. If you define a function like this:

    Person.prototype.setAge = function( newAge){
       this.age = newAge();
    }
    

    Any function (or any variable for that matter) defined in Person's prototype object will also be accessible to any object created using that constructor. Plus, the this variable will be the object making that call.

    So, if you have:

    function Person( age ){
      this.age = age;
    }
    
    Person.prototype.setAge = function( newAge){
    
       //`this` at this point is the object "calling" <-- This will throw an error if left uncommented.
       this.age = newAge();
    }
    
    var pavlo = new Person( 23 );
    console.log( pavlo.age );
    
    // pavlo is making the call. So, within `setAge()`, `this` will be `pavlo`
    pavlo.setAge( 26 );
    

    So, for your solution:

    function test(root){
      this.HTML = getAllHTML();
      // etc.
    }
    

    And then your alert should be:

    test.prototype.nextSlide = function(){
      alert(this.HTML.current);
    }
    

    Note that in Javascript you should have constructor functions starting with a capital letter (see: Test rather than test).

    If you don't want HTML to be accessible from the outside, convention says that you normally put an underscore in front of the variable's name (call it _HTML ).

    There are other ways of doing it, if you absolutely have to keep that variable hidden away from the developers. However, it's not exactly straightforward and -- most developers would say -- definitely not worth the effort.

    A couple of good reads (but, I must say that I read them when I was starting with JS, and they confused the hell out of me at the time :D )

    UPDATE: This is another fantastic article on this matter: https://blog.jcoglan.com/2012/01/19/the-cost-of-privacy

    Enjoy!