简体   繁体   中英

javascript: can I define a “private” variable using prototype?

I want to use a unique private variable for each "instance" (I hope that this is the right term in Javascript), but both instances appear to use the same private variable.

func = function(myName)
{
    this.name = myName
    secret = myName

    func.prototype.tellSecret = function()
    {   return "the secret of "+this.name+" is "+secret
    }
}

f1 = new func("f_One")
f3 = new func("f_3")

console.log(f3.tellSecret()) // "the secret of f_3 is f_3" OK
console.log(f1.tellSecret()) // "the secret of f_One is f_3" (not OK for me)

I saw a solution but

this would mean duplicating the function on every instance, and the function lives on the instance, not on the prototype.

Another author says about the same solution

That's still not quite traditional classly Javascript, which would define the methods only once on Account.prototype.

So, is there a solution where

  • every instance can have unique values for secret
  • secret is only accessible for methods that are defined in the constructor and
  • functions are not duplicated for every instance

?

The problem is that you're replacing your prototype function each time the constructor is called.

With old-style closure-based privacy, you can't access "private" members from prototype methods, because only functions defined in the constructor closing over them can use them. So you end up remaking the functions for each instance (which isn't as bad as it sounds, but isn't great).

function Example(name) {
    this.name = name;
    var secret = name; // Using `var` here on the basis this is ES5-level code

    // This can't be a prototype function
    this.tellSecret = function() {
        return "the secret of " + this.name + " is " + secret;
    };
}

Two options for you:

1) Use a transpiler like Babel, class syntax, and private fields (likely to be in ES2021, in use for a fair bit time now via transpiling):

class Example {
    #secret;

    constructor(name) {
        this.name = name;
        this.#secret = name;
    }

    tellSecret() {
        return "the secret of " + this.name + " is " + this.#secret;
    }
}

const f1 = new Example("f_One");
const f3 = new Example("f_3");

console.log(f3.tellSecret()) // "the secret of f_3 is f_3"
console.log(f1.tellSecret()) // "the secret of f_One is f_One"

2) Use a WeakMap (ES2015+) containing the secret information

const secrets = new WeakMap();
class Example {
    constructor(name) {
        this.name = name;
        secrets.set(this, name);
    }

    tellSecret() {
        return "the secret of " + this.name + " is " + secrets.get(this);
    }
}

const f1 = new Example("f_One");
const f3 = new Example("f_3");

console.log(f3.tellSecret()) // "the secret of f_3 is f_3"
console.log(f1.tellSecret()) // "the secret of f_One is f_One"

You put secrets where only Example has access to it.

You can use a WeakMap without using class syntax too, but if you're creating constructor functions with associated prototypes, class is simpler than function Example and assigning to properties on Example.prototype .

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