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?

asked Jun 20, 2011 at 14:14
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.)

answered Jun 20, 2011 at 14:33
2
  • faster than me and best answer...+1! Commented Jun 20, 2011 at 14:34
  • That's a pretty hacky way of doing it. I like it. Commented Jun 20, 2011 at 14:40
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/

answered Jun 20, 2011 at 14:24
0
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;
 };
};
answered Jun 20, 2011 at 14:26
2
  • 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). Commented Jun 20, 2011 at 14:30
  • @JAAulde Thanks I must've added that when I was writing my own. Updated to be similar to Rocket's original question. Commented Jun 20, 2011 at 14:34
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.

answered Jun 20, 2011 at 14:33
2
  • Cool, this works (in Chrome 13). Didn't know about the get length() syntax. Commented Jun 20, 2011 at 14:41
  • 1
    It works in a lot of browsers: Chrome 12, FF4. Not yet implemented in IE though. Commented Jun 20, 2011 at 14:43
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();
 };
};
answered Jun 20, 2011 at 14:25
2
  • 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. Commented Jun 20, 2011 at 14:29
  • ah, my bad. I missed the var. Thanks for letting me know. Commented Jun 20, 2011 at 14:32
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
 }
})
answered Jun 27, 2018 at 8:28
-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();
 };
};
gen_Eric
228k42 gold badges303 silver badges343 bronze badges
answered Apr 18, 2013 at 13:00
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.