简体   繁体   中英

Javascript prototype inheritance private method

I've been investigating multiple leveles of inheritance with "private" variable in each "class" in JavaScript, but run into this peculiar singularity:

function Ammo() {
    var a = 0;
    this.get_ammo = function() {
        return a;
    };

    this.add_to_ammo = function() {
        a = a+1
        return a;
    };

    this.clean_ammo = function() {
        return a=0;
    }
}

function Weapon() {
    var a =0;
}

function Gun() {
    var a = 0;
    this.fire = function(){
        console.log("Bang");
    }
}

Weapon.prototype = new Ammo();
Weapon.prototype.constructor  = Weapon();

Gun.prototype = new Weapon();
Gun.prototype.constructor = Gun();

var a = new Ammo();
var w = new Weapon();
var g = new Gun();

a.add_to_ammo()
a.add_to_ammo()
a.add_to_ammo()
console.log(w.get_ammo())
// At this point I get 0, as expected. But after
w.add_to_ammo()
w.add_to_ammo()
w.add_to_ammo()
console.log(g.get_ammo())
// But here I get 3!

Can somebody explain why I get 3 after

console.log(g.get_ammo())

I thought that objects a, w, g are independent, so are their fields.

Also I found out that if I change

var a = 0;

to

this.a = 0;

I get expected result. fields of the object are unbound to their parents fields.

var a is defined in Ammo , but var a in the other constructors does absolutely nothing. The a that's being modified when you call the method no matter which instance is always the same a that was captured in the closure in Ammo .

You can't have private variables like you want in JavaScript, and that's ok. The most common way to do it is to make the variable public, and prefix it with an underscore, to mark it as "internal":

function Ammo() {
  this._ammo = 0;
}

Then add the methods to the prototype and use this._ammo to reference that variable:

Ammo.prototype.getAmmo = function() {
  return this._ammo
}

Then you can inherit with Object.create :

Weapon.prototype = Object.create(Ammo.prototype);

And in the constructor "call super":

function Weapon() {
  Ammo.call(this) // gets own "_ammo"
}

Also, you are not setting up the constructor function properly. You should assign a function, not call it:

Weapon.prototype.constructor = Weapon;
Gun.prototype.constructor = Gun;

I don't have enough rep points to comment on @elclanrs answer, so forgive me.

His answer is all correct, but the most pertinent piece of information is the last

Also, you are not setting up the constructor function properly. You should assign a function, not call it:

Weapon.prototype.constructor = Weapon;
Gun.prototype.constructor = Gun;

your variables that are declared inside the scope of the function closure ARE IN FACT PRIVATE! however, you never properly instantiated you subclass objects, so you had a frankenstein thing going on: one object, lots of body parts.

Other than that there is nothing inherently wrong with your code, it's just not the way people usually write "Classes" and I won't explain why in the context of this question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM