7

I want to add a static function to a class in EcmaScript 5 JavaScript. My class definition looks as follows:

var Account = {};

Object.defineProperty(Account, 'id', {
    value : null
});

And I would create a new instance like this:

var theAccount = Object.create(Account);
theAccount.id = 123456;

Now I want to add a static function to the Account class. If I had created the Account class using a constructor function and the prototype property like this:

var Account = function () {
    this.id = null;
};

...I could just do:

Account.instances = {};

Account.createInstance = function () {
    var account = new Account();
    account.id = uuid.v4();
    Account.instances[account.id] = account;
    return account;
};

But since I am using Object.defineProperty and not the prototype property to add members, Account.instances and Account.createInstance would also be instantiated when calling Object.create and therefore be properties of the instance.

How do i add a static member to a class when using EcmaScript 5 style object creation?

Max Kueng
  • 280
  • 4
  • 10

4 Answers4

5

For ES 5 if you want static methods:

// A static method; this method only 
// exists on the class and doesn't exist 
// on child objects
Person.sayName = function() {
    alert("I am a Person object ;)");  
};

// An instance method; 
// All Person objects will have this method
Person.prototype.setName = function(nameIn) {
    this.name = nameIn;  
}

see @https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/

Combine
  • 3,894
  • 2
  • 27
  • 30
1

You seem to have some different things mixed up. The prototype is going to be shared fallback properties. If you want to define a static (I assume by what you're doing you mean non-writable property?) you can use defineProperty in the constructor.

function Account(){
  Object.defineProperty(this, 'id', {
    value: uuid.v4()
  });
  Account.instances[this.id] = this;
}

Account.instances = {};

Account.prototype.id = null;


var account = new Account;
  • Thanks @benvie. But what if I want to use `Object.create` to create objects instead of `new`? Doesn't `Object.create` make the `new` operator obsolete in EcmaScript 5? – Max Kueng Jul 27 '12 at 13:25
  • 1
    @MaxKueng - no, they do different things. `Object.create()` is for dealing with 'classes' (not really classes) declared as objects, while `new` is for instantiation, which is always of functions, i.e. constructors. – Mitya Jul 27 '12 at 13:28
  • 1
    Object.create is for when you want to create an object but not initialize it. If you want to initialize it then use a constructor, that's the whole point of a constructor. Object.create is even implemented using `new` in the V8 source code. `var obj = new $Object(); obj.__proto__ = proto;` https://github.com/v8/v8/blob/master/src/v8natives.js#L1038 –  Jul 27 '12 at 13:45
  • @benvie: I don't think you could say that. It is implemented using the `__proto__` property, and they could've use `{}` instead of `new $Object();` as well. – Bergi Jul 27 '12 at 13:51
  • `{}` is the same thing as `new Object` except it's not susceptible to being overridden. That's the point I was making. Avoiding the `new` keyword for the sake of avoiding it is pointless, there's no benefit. You're doing it one way or another. –  Jul 27 '12 at 14:08
  • Thanks. I thought `Object.create` was the new `new`. I will read some more about both of them. It probably doesn't make to use `Object.create` just for the sake of it. I really like `Object.defineProperty` with getters and setters. But I think I can also use them on the prototype with constructor functions. Lets see. – Max Kueng Jul 28 '12 at 17:10
1

But since I am using Object.defineProperty and not the prototype property to add members, Account.instances and Account.createInstance would also be instantiated when calling Object.create and therefore be properties of the instance.

Any static properties or methods declared on the source object will not be deemed properties of the instance - they will be read from the prototype.

    var obj = {};
    obj.static = function() { alert('hello'); }
    var instance = Object.create(obj);
    instance.ownProperty = 'hello';
    alert(!!instance.static); //true - it has .static
    alert(instance.hasOwnProperty('static')); //false - but it's not its own
    alert(instance.hasOwnProperty('ownProperty')); //true
Mitya
  • 33,629
  • 9
  • 60
  • 107
  • Wooooh! I have just learned that `!!` will convert something to a boolean without negating it. Thanks. Never thought of this. – Max Kueng Jul 28 '12 at 17:04
  • Yeah it's a trick to test something's [truthy](http://www.mitya.co.uk/blog/2011/Apr/Twisted-logic-understanding-truthy-and-falsy-174) value. – Mitya Jul 28 '12 at 17:11
1

You can't.

My class definition looks as follows var Account = {};

That's not a class (if we would call the classical model like that), but just a prototoype object. And as you only have that, you will need to use other variables for static members like an instances-cache or a create function:

var Account = {...};
var instances = [];
function createAccount(){...}

You could namespace them, of course:

var Account = {
    proto: {...},
    instances: [],
    instantiate: function create(){...}
};

...but that looks very close to the classical pattern, doesn't it? The only difference would be that you had a create function on a namespace object instead of a constructor function as the namespace object.

You might also be interested in the question Object.create Prototype Chains, where I have discussed a full inheritance model working like that, with create and inherit methods that all "class objects" inherit from a base.


Further answer on your question in the comments:

Doesn't Object.create make the new operator obsolete in EcmaScript 5?

No. The new keyword does two things: Set up the prototype chain of the new instance, and apply the the constructor function. Object.create does only the first thing, so you can use it when you dont need a function (or dont want it to execute).

In your case, you have such a function, so the classical model wouldn't be wrong here as well. See also Using "Object.create" instead of "new".

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks! I think I have to read some more articles on it to fully understand what each object creation method does. This post was very helpful. – Max Kueng Jul 28 '12 at 17:01