7

Let's say I have a JavaScript object:

function a(){ var A = []; this.length = function(){ return A.length; }; this.add = function(x){ A.push(x); }; this.remove = function(){ return A.pop(); }; }; 

I can use it like so:

var x = new a(); x.add(3); x.add(4); alert(x.length()); // 2 alert(x.remove()); // 4 alert(x.length()); // 1 

I was trying to make .length not a function, so I could access it like this: x.length, but I've had no luck in getting this to work.

I tried this, but it outputs 0, because that's the length of A at the time:

function a(){ var A = []; this.length = A.length; //rest of the function... }; 

I also tried this, and it also outputs 0:

function a(){ var A = []; this.length = function(){ return A.length; }(); //rest of the function... }; 

How do I get x.length to output the correct length of the array inside in the object?

1

7 Answers 7

5

You could use the valueOf hack:

this.length = { 'valueOf': function (){ return A.length; }, 'toString': function (){ return A.length; } }; 

Now you can access the length as x.length. (Although, maybe it's just me, but to me, something about this method feels very roundabout, and it's easy enough to go with a sturdier solution and, for example, update the length property after every modification.)

Sign up to request clarification or add additional context in comments.

2 Comments

faster than me and best answer...+1!
That's a pretty hacky way of doing it. I like it.
3

If you want A to stay 'private', you need to update the public length property on every operation which modifies A's length so that you don't need a method which checks when asked. I would do so via 'private' method.

Code:

var a = function(){ var instance, A, updateLength; instance = this; A = []; this.length = 0; updateLength = function() { instance.length = A.length; } this.add = function(x){ A.push(x); updateLength(); }; this.remove = function(){ var popped = A.pop(); updateLength(); return popped; }; }; 

Demo: http://jsfiddle.net/JAAulde/VT4bb/

Comments

2

Because when you call a.length, you're returning a function. In order to return the output you have to actually invoke the function, i.e.: a.length().

As an aside, if you don't want to have the length property be a function but the actual value, you will need to modify your object to return the property.

function a() { var A = []; this.length = 0; this.add = function(x) { A.push(x); this.length = A.length; }; this.remove = function() { var removed = A.pop(); this.length = A.length; return removed; }; }; 

2 Comments

This is a valid answer, except that you've modified the return value of the .remove() method (not by any design flaw in your answer, though).
@JAAulde Thanks I must've added that when I was writing my own. Updated to be similar to Rocket's original question.
1

While what everyone has said is true about ES3, that length must be a function (otherwise it's value will remain static, unless you hack it to be otherwise), you can have what you want in ES5 (try this in chrome for example):

function a(){ var A = [], newA = { get length(){ return A.length;} }; newA.add = function(x){ A.push(x); }; newA.remove = function(){ return A.pop(); }; return newA; } var x = a(); x.add(3); x.add(4); alert(x.length); // 2 alert(x.remove()); // 4 alert(x.length); // 1 

You should probably use Object.create instead of the function a, although I've left it as a function to look like your original.

2 Comments

Cool, this works (in Chrome 13). Didn't know about the get length() syntax.
It works in a lot of browsers: Chrome 12, FF4. Not yet implemented in IE though.
0

I don't think you can access it as a variable as a variable to my knoledge cannot return the value of a method, unless you will hijack the array object and start hacking in an update of your variable when the push/pop methods are called (ugly!). In order to make your method version work I think you should do the following:

function a(){ this.A = []; this.length = function(){ return this.A.length; }; this.add = function(x){ this.A.push(x); }; this.remove = function(){ return this.A.pop(); }; }; 

2 Comments

My current, 'method', version works fine. A did not have this. in front of it, because that makes it a 'private' member of the function.
ah, my bad. I missed the var. Thanks for letting me know.
0

These days you can use defineProperty:

let x = {} Object.defineProperty(x, 'length', { get() { return Object.keys(this).length }, }) x.length // 0 x.foo = 'bar' x.length // 1 

Or in your specific case:

Object.defineProperty(x, 'length', { get() { return A.length } }) 

Comments

-1
function a(){ this.A = []; this.length = function(){ return this.A.length; }; this.add = function(x){ this.A.push(x); }; this.remove = function(){ return this.A.pop(); }; }; 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.