Skip to main content
TᴀW
Legend
March 6, 2012
Question

Javascript question about objects

  • March 6, 2012
  • 2 replies
  • 2429 views

Hi,

Let's say I've created a new object. One of the properties of my object

is an array. I would like another property to return the length of that

array. How do I do this.

For instance here's some code (and I hope that the email interface

doesn't screw this up so badly to make it unreadable. I'm going to avoid

using square brackets as well by using round ones instead even though

it's a syntax error, since square ones are known not to work with email.)

function test(){

this.a = new Array();

this.b = this.a.length;

}

x = new test();

x.a(0) = 3;

x.a(1) = 3;

x.b;

Returns 0. In other words, just setting this.b = this.a.length doesn't

not get updated automatically as this.a is added to.

Now, I tried turning this.b into a method (ie this.b = function(){return

this.a.length) and that works, but then to get the length I keep having

to refer to myObject.b().

How can I avoid that? How can I have a built-in length property for an

object.

Hope this is clear and has come out legibly via email. Apologies in

advance if it hasn't.

Thanks,

Ariel

This topic has been closed for replies.

2 replies

Marc Autret
Legend
March 7, 2012

Hi all,

1) About the original question—which doesn't regard prototype inheritance in itself: "How can I have a built-in length property for an object"—I think the most obvious approach is to directly use an Array as the base object. Since any Array is an Object you can append methods and properties to it while keeping benefit from the whole array's API:

var myData = [];

myData.myProp = 'foo';

myData.myMeth = function(){ return [this.myProp, this.length, this.join('|')]; };

// Usage

// ---

myData[0] = 10;

myData[1] = 20;

alert( myData.myMeth() ); // => foo,2,10|20

// etc.

2) Now, if for whatever reason you cannot use the previous technique or need to deal with a precustomized Object structure such as:

var myObj = {

    items: [],

    meth: function(){ alert("Hello World!"); },

    // etc.

    };

then the challenge is more difficult for the reasons that Jeff mentioned above. You can anyway mimic a kind of 'binding' mechanism this way:

// The original obj

// ---

var myObj = {

    items: [],

    meth: function(){ alert("Hello World!"); }

    };

// Adding length as a 'fake property' (getter and setter)
// ---

(myObj.length = function F(n)

{

    if( !F.root )

        {

        (F.root=this).watch('length', function(_,ov,nv){ F(nv); return ov; });

        F.valueOf = function(){ return F().valueOf(); };

        F.toString = function(){ return F().toString(); };

        }

    if( 'undefined' == typeof n )

        n = F.root.items.length >>> 0;

    else

        F.root.items.length = n;

    return n;

}).call(myObj);


// Usage

// ---

myObj.meth(); // => Hello World!

myObj.items[0] = 10;

myObj.items[1] = 20;

alert( myObj.length ); // => 2

var x = myObj.length-1; // works too, thanks to F.valueOf

alert( x ); // => 1

myObj.length = 5; // testing the setter

alert( myObj.length ); // => 5

alert( myObj.items ); // => 10,20,,,

Of course it's totally unreasonable to implement such an artillery just for the convenience of writing myObj.length instead of myObj.length()—and myObj.length=x instead of myObj.length(x)—so I only suggest this for the sake of experimentation.

@+

Marc

John Hawkinson
Inspiring
March 8, 2012

Marc:

        (F.root=this).watch('length', function(_,ov,nv){ F(nv); return ov; });

I had no idea that ExtendSCript had .watch() and .unwatch().

That's kind of weird. I guess I don't understand where Adobe's ExtendScript implementation comes from.

Mozillla implies it's fairly nonstandard.

Thanks for pointing that out!

Inspiring
March 6, 2012

Until ExtendScript supports ECMAScript 5—does anyone know if this is going to happen, by the way?—which includes getter and setter properties, calling a function is the only way to do it.

(Defining b() on the prototype, so that all the objects made from Test() will share the same function, is  the more efficient and accepted way to do it.)

function Test(){

    this.a = [];

}

Test.prototype.b = function () {

    return this.a.length;   

};

var x = new Test();

x.a[0] = 3;

x.a[1] = 3;

x.b();

Jeff

TᴀW
TᴀWAuthor
Legend
March 6, 2012

Thanks Jeff.

I don't understand what the difference is between hooking the function

onto prototype vs. making it part of the constructor is? Can you elaborate?

Ariel

id-extras.com | InDesign tools & scripts for typesetters, form designers, and translators
Inspiring
March 6, 2012

All objects created with new from Test() will share Test()'s prototype. So if you define your function there, all objects created from Test() will have access to the same function—by looking for it up the prototype chain—and it will only be defined once. If you define it in your constructor, each new object will have a separate copy of the function. It's a matter of efficiency, really. (And flexibility, I suppose: you could redefine the prototype's function later, and all objects that share it would then have access to the updated function.)

There's a lot of information about this out there, though I'm having a hard time putting my hands on a good article at the moment.