Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS non-enumerable function

I'm trying to define a non-enumerable toJSON function on a prototype object without much luck. I'm hoping for something similar to ECMAScript 5 toJSON:

Object.defineProperty(obj, prop, { enumerable: false });

However this defines it as a property which cannot be accessed as a method.
[EDIT: Nick is wrong; it can be accessed as a method. His mistake was in code that is not shown in this question - see his comments on answers below, for details.]

I was hoping to be able to define the function in a non-enumerable fashion, as I was planning to define in the prototypes of all primitive types (String, Number, Boolean, Array, and Object), so that I can recursively apply the function through complex objects.

The end goal here is to be able JSONify a Backbone model/collection with nested collections recursively.

I guess in total I have two main questions:

  1. Is it possible to define a non-enumerable function on a prototype? If so how?
  2. Is there a better way to JSONify nested Backbone models?
like image 667
Nick Mitchinson Avatar asked Jul 03 '13 02:07

Nick Mitchinson


2 Answers

I don't get it, why can't you access it as a method?

var foo = {};

Object.defineProperty(foo, 'bar', {
    enumerable: false,
    value: function () {console.log('foo.bar\'d!');}
});

foo.bar(); // foo.bar'd!

If you wanted it on the prototype, it's as easy as

Object.defineProperty(foo.prototype, /* etc */);

or even directly in Object.create

foo.prototype = Object.create(null, {
    'bar': {value: function () {/* ... */}}
});

However, unless you're creating instances of foo, it won't show up if you try to foo.bar, and only be visible as foo.prototype.bar.

If foo has it's own prototype (e.g. foo = Object.create({})), you can get it with Object.getPrototypeOf, add the property to that and then foo.bar would work even if it is not an instance.

var proto = Object.getPrototypeOf(foo); // get prototype
Object.defineProperty(proto, /* etc */);

You can see visibility of enumerable vs non-enumerable properties here.

like image 51
Paul S. Avatar answered Sep 29 '22 13:09

Paul S.


Paul S. is right about needing to set the property definition's value instead of a get, but I wanted to add that you don't need to pass enumerable: false, because false is the default for that option in Object.defineProperty() The answer can be simplified to:

var foo = {};    

Object.defineProperty(foo, 'bar', {
    value: function(){ console.log('calling bar!'); }
});

foo.bar();
like image 25
csuwldcat Avatar answered Sep 29 '22 13:09

csuwldcat