0

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();
kevinius
  • 4,232
  • 7
  • 48
  • 79
  • Maybe this answer can help you out understanding what prototype, constructor functions and the `this` variable is: http://stackoverflow.com/a/16063711/1641941 It has some patterns in there for private variables but it's better you start with the introduction, maybe mess around with the Hamster code in there. Let me know if you have any questions and I'll be happy to answer them. – HMR Nov 23 '13 at 02:02

2 Answers2

1

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!

Bradyo
  • 63
  • 7
Merc
  • 16,277
  • 18
  • 79
  • 122
0

You're trying to access the property inside Test, but test is not part of Expojs. Then you're trying to extend the prototype of Expojs which is a bad idea because it's never a good idea to create new members for code which you don't control.

If you want nextSlide to be part of Test then you have to use Test.prototype.nextSlide(), which would create a new prototype member for the test object called nextSlide(). Then the public instance members would be accessible, such as this.getallHTML = function(){//usual stuff};

You need to use this keyword for the variables you want to access on a basic level. After that there is the issue of abstraction which you have to consider if you want to protect the code from being used wrongly by others.

I've just been doing lots of tutorials on object orientation in JavaScript and as you can see I've learnt loads on this so far (still learning so I may not have everything right here), but I recommend doing some more study.

nircraft
  • 8,242
  • 5
  • 30
  • 46
Adamantus
  • 813
  • 1
  • 12
  • 30