简体   繁体   中英

Set length property of JavaScript object

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?

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.)

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/

Because when you call a.length , you're returning a function. In order to return the output you have to actually invoke the function, ie: 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;
  };
};

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.

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
  }
})

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();
    };
};
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();
    };
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM