0

lick() is a private method of Cat. Unfortunately, Cat's this.paw is not accessible in lick(). Is there a simple way to create a private method that has access to the member variables of its containing class?

<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<p id="catStatus">???</p>
<script>
function Cat() {

    this.paw;

    var lick = function() {
        alert(this.paw);
        if(this.paw == "sticky") {
            alert("meow");
            document.getElementById("catStatus").innerHTML = "*Slurp*";
        }
    };

    this.beCat = function() {
        this.paw = "sticky";
        lick();
    }
}
var kitty = new Cat();
kitty.beCat();
</script>
</body>
</html>

Result

David Winiecki
  • 4,093
  • 2
  • 37
  • 39

3 Answers3

2

The value of this depends on how you call the method.
Since you're not calling the method on the object instance, this becomes the global object.

Instead, you need to save this in a variable:

function Cat() {
    this.paw = ...;

    var me = this;

    var lick = function() {
        alert(me.paw);
        if(me.paw == "sticky") {
            alert("meow");
            document.getElementById("catStatus").innerHTML = "*Slurp*";
        }
    };

    this.beCat = function() {
        this.paw = "sticky";
        lick();
    }
}
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Actually, `this` does not refer to the global object within lick(), it refers to the lick function itself. – andersand Nov 18 '12 at 13:40
  • Honest question: why did you add ellipsis to the declaration of this.paw? Declaring this.paw without a value prevents an exception when referencing the variable. this.paw = ...; produces a syntax error. Maybe I should use this.paw = undefined; instead. – David Winiecki Nov 22 '12 at 03:55
  • @andersand It would make since to me that `this` would refer to lick inside lick, but if you `alert(this.toString())` inside `lick`, it actually says "[object Window]", which is the same thing it says in a ` – David Winiecki Nov 22 '12 at 04:04
1

There are a couple ways to solve this. The problem is that the context inside of lick is not the instance of cat. You can either:

Use the call method to set the context

this.beCat = function() {
    this.paw = "sticky";
    lick.call(this);
};

or use closure

var instance = this;
var lick = function() {
    alert(instance.paw);
    if(instance.paw == "sticky") {
        alert("meow");
        document.getElementById("catStatus").innerHTML = "*Slurp*";
    }
};
Hemlock
  • 6,130
  • 1
  • 27
  • 37
  • Is that really a closure? It doesn't seem to me to resemble [this description](http://www.javascriptkit.com/javatutors/closures.shtml) of a closure. But I'm really not sure. – David Winiecki Nov 22 '12 at 03:29
  • Sure it is, it's a closure over the variable `instance` inside the function `lick`. – Hemlock Nov 23 '12 at 23:27
1

The context of this depends upon who called the function. In this case it is beCat. You can however explicitly specify the this scope by using call.

In your case:

    this.beCat = function () {
        this.paw = "sticky";
        lick.call(this);
    }

Or you can store the this in a variable.

You can read more about the this scope/how it works here.

The Heatherleaf
  • 128
  • 1
  • 2
  • 11