简体   繁体   中英

Is there a Class equivalent to prototype variables on Functions?

If I have the following code:

function Thing() {}
Thing.prototype.cache = {};

var a = new Thing();
var b = new Thing();

a.cache === b.cache // true

How might I re-write this using proper Classes ?

I know about public class fields , but those are defined on the instance rather than on the class prototype.

// For Example:
class Thing {
  cache = {}
}

var a = new Thing();
var b = new Thing();

a.cache === b.cache // false

There's no class syntax to put non-methods on the prototype, you'll have to slap them on afterwards, like this:

 class Thing {} Thing.prototype.cache = {} // Example usage // const thing1 = new Thing() const thing2 = new Thing() thing1.cache.x = 2 console.log(thing2.cache.x)

However, putting mutable data on the prototype is seen by many as magical and difficult to follow. Here's another way to achieve a very similar effect.

 // This can alternativly be a static, private variable on the class. const thingCache = {} class Thing { cache = thingCache } // Example usage // const thing1 = new Thing() const thing2 = new Thing() thing1.cache.x = 2 console.log(thing2.cache.x)

But, what I would really recommend is to just make this property a static property on the class - that's what static properties are for, sharing a single piece of data between many instances.

 class Thing { static cache = {} } // Example usage // Thing.cache.x = 2 console.log(Thing.cache.x) // In some rare scenarios where you only have the instance, // and not the original class, you can still retrieve the original class const thing1 = new Thing() const thing2 = new Thing() thing1.constructor.cache.x = 2 console.log(thing2.constructor.cache.x)

What you have implemented is called class field , as you noticed in your case it's an equivalent of:

class Thing {
  constructor() {
    this.cache = {};
  }
}

You have no other choice than attaching it to the prototype just like you'd do in ES5, because everything you declare inside a class is either:

  • A class field (attached to the instance)
  • A method (attached to the prototype)
  • A static field (attached to the class)

 class Thing { } Thing.prototype.cache = {}; const obj1 = new Thing; const obj2 = new Thing; console.log(obj1.cache === obj2.cache);

I have posted a similar question here: Not able to update a class property in ES6

As a side note, as you're not using a constructor , the class is needless so you could write this:

 const proto = { cache: {} }; const obj1 = Object.create(proto); const obj2 = Object.create(proto); console.log(obj1.cache === obj2.cache);

You want to create a static class field

Then define getters and setters based off the class name.

Public static fields are useful when you want a field to exist only once per class, not on every class instance you create. This is useful for caches, fixed-configuration, or any other data you don't need to be replicated across instances.

Public static fields are declared using the static keyword. They are added to the class constructor at the time of class evaluation using Object.defineProperty() . They are accessed again from the class constructor.

  • Fields without initializers are initialized to undefined.
  • Public static fields are not reinitialized on subclasses, but can be accessed via the prototype chain.
  • When initializing fields, this refers to the class constructor. You can also reference it by name, and use super to get the superclass constructor (if one exists).

 class Thing { static _cache = {}; get cache() { return Thing._cache; } set cache(newValue) { Thing._cache = newValue; } } var a = new Thing(); var b = new Thing(); b.cache.key = "value"; console.log(a.cache === b.cache); console.log(a.cache)

As Scotty Jamison said, the class syntax still does not provide a way to create fields on the prototype itself, so you'll have to do it with [class].prototype.field . However, if you wish to do so within the class declaration itself, you can use static blocks:

class Thing {
    static {
        this.prototype.boofar = {};
    }
}

Code inside a static block will run when the class is initialized, with this bound to the class itself. This is arguably more confusing than just assigning the value after the class declaration, as using static might suggest a static property, not an inherited one. Still, it's nice for the class to not depend on external code.

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