0

EDIT: This is NOT a duplicate. While the answer is great, the question applies to the context of loopbackjs. There, most properties are accessed asynchronously. I tried the proposed solution and it doesn't work because the property count is accessed asynchronously:

node.__count__children(function(err, count) {
   if (err) {
     console.log(err);
     return;
   }

   return count;
});

This means I can't rely on the language features directly, but must account for asynchronicity. EDIT END

In django/python, I could define a property like so:

@property
def count_children(self):
    return len(self.children)

Is this possible in javascript as well? Actually I need it in the context of loopback, but maybe it's a feature of the language?

I have tried manipulating the prototype:

Node.prototype.count_children = function() {
     return this.children.length;
}

But this just adds a function count_children() to the object, it doesn't put the value of the function as property. Is that possible in javascript?

transient_loop
  • 5,984
  • 15
  • 58
  • 117
  • All methods are just properties with function values in JavaScript. Do you want one that is not inherited, or what do you mean? – Bergi Dec 15 '15 at 02:41
  • 1
    If it's async, you need to provide a callback function and as a property, there's no way to pass a callback. –  Dec 16 '15 at 15:29
  • I think it's fair to say then that it can't be done, thus maybe you want to provide your comment as an answer? Just to close the question @squint – transient_loop Dec 17 '15 at 22:34
  • @faboolous: I updated the answer, and also added some info about returning a Promise, which may satisfy your needs. –  Dec 17 '15 at 23:14

1 Answers1

2

I think you're saying you want a "getter" behavior on a property. Basically you want to call a function without the parens. If so, you can define it using Object.defineProperty():

Object.defineProperty(Node.prototype, "count_children", {
  get: function() {
    return this.children.length;
  }
});

document.body.appendChild(document.createElement("pre")).textContent = "Total <li> count: " + 
  document.querySelector("ul").count_children;
<ul>
  <li>foo
  <li>bar
  <li>baz
</ul>

If the behavior you need to wrap is asynchronous, it would seem to require a callback, and therefore a getter property wouldn't provide the chance to assign one.

If the API you're wrapping returns something like a "Promise" object, you can still return that. You could also return your own Promise, whether as part of the new ECMAScript 6, as an external library, or as your own simpler implementation.

  • thanks for this answer, which would be great in a pure javascript environment, but I am accessing the property in loopbackjs, where the count_children property can only be accessed asynchronously – transient_loop Dec 15 '15 at 02:56