views:

494

answers:

6

Is there a way to get a get/set behaviour on an array? I imagine something like this:

var arr = ['one', 'two', 'three'];   
var _arr = new Array();

for (var i=0; i < arr.length; i++) {
arr[i].__defineGetter__('value',
function(index) {
    //Do something
    return _arr[index];
});
arr[i].__defineSetter__('value',
function(index, val) {
    //Do something
    _arr[index] = val;
});
};
A: 

I can't imagine it would work. __defineGetter__ and __defineSetter__ were proposals to the standard that have been ditched in favour of Object.defineProperty(). To quote the specification:

The defineProperty function is used to add an own property and/or update the attributes of an existing own property of an object. When the defineProperty function is called, the following steps are taken:

  1. If Type(O) is not Object throw a TypeError exception.
  2. Let name be ToString(P).
  3. Let desc be the result of calling ToPropertyDescriptor with Attributes as the argument.
  4. Call the [[DefineOwnProperty]] internal method of O with arguments name, desc, and true.
  5. Return O.

Point 1 looks like the most relevant here. If Type(O) is not Object throw a TypeError exception. An array would return type Array, not Object.

Andy E
+2  A: 

You can add whatever methods you like to an Array, by adding them to Array.proptotype. Here's an example that adds a getter and setter

Array.prototype.get = function(index) {
  return this[index];
}

Array.prototype.set = function(index, value) {
  this[index] = value;
}
Don
Sounds very functional and compatible, but If you wanna tweak an Array for good, than you don't want an Array anymore, but a class as @jpabluz said
Fabiano PS
But what I want is for the array to seemingly operate as before, so I can do arr[0] = "value" and not arr.set() etc.. and still execute some code when that is done.This is the way getter/setters function for normal properties.
Martin Hansen
+1  A: 

Why not create a new class for the inner objects?

var a = new Car();

function Car()
{
   // here create the setters or getters necessary
}

And then,

arr = new Array[a, new Car()]

I think you get the idea.

jpabluz
`new Array[ ... ]` is not syntactically correct. You have to use parens for instead: `new Array( ... )`. Or just leave out the `new Array` and just use the ` [ ... ]` literal notation.
Šime Vidas
A: 

Array access is no different to normal property access. array[0] means array['0'], so you can define a property with name '0' and intercept access to the first array item through that.

However, that does make it impractical for all but short, more-or-less-fixed-length Arrays. You can't define a property for “all names that happen to be integers” all in one go.

bobince
A: 

I hope it helps.

Object.extend(Array.prototype, {
    _each: function(iterator) {
                    for (var i = 0; i < this.length; i++)
                    iterator(this[i]);
                },
    clear: function() {
                    this.length = 0;
                    return this;
                },
    first: function() {
                    return this[0];
                },
    last: function() {
                return this[this.length - 1];
                },
    compact: function() {
        return this.select(function(value) {
                                                return value != undefined || value != null;
                                                }
                                            );
        },
    flatten: function() {
            return this.inject([], function(array, value) {
                    return array.concat(value.constructor == Array ?
                        value.flatten() : [value]);
                    }
            );
        },
    without: function() {
        var values = $A(arguments);
                return this.select(function(value) {
                        return !values.include(value);
                }
            );
    },
    indexOf: function(object) {
        for (var i = 0; i < this.length; i++)
        if (this[i] == object) return i;
        return -1;
    },
    reverse: function(inline) {
            return (inline !== false ? this : this.toArray())._reverse();
        },
    shift: function() {
        var result = this[0];
        for (var i = 0; i < this.length - 1; i++)
        this[i] = this[i + 1];
        this.length--;
        return result;
    },
    inspect: function() {
            return '[' + this.map(Object.inspect).join(', ') + ']';
        }
    }
);
Martinez
A: 

I looked up in John Resig's article JavaScript Getters And Setters, but his prototype example didn't work for me. After trying out some alternatives, I found one that seemed to work. You can use Array.prototype.__defineGetter__ in the following way:

Array.prototype.__defineGetter__("sum", function sum(){
var r = 0, a = this, i = a.length - 1;
do {
    r += a[i];
    i -= 1;
} while (i >= 0);
return r;
});
var asdf = [1, 2, 3, 4];
asdf.sum; //returns 10

Worked for me in Chrome and Firefox.

rolandog