prototype object and arrays - I'm confused

Discussion in 'Javascript' started by Piotr K, Aug 24, 2009.

  1. Piotr K

    Piotr K Guest

    I came across a strange problem or I just don't understand how
    prototype object works.. but first things first - take a look at this
    code

    var A = function() {}

    A.prototype.r = [10];

    var a1 = new A, a2 = new A;

    a2.r[0] = 20;

    alert(a1.r[0]); // = 20 WTF ?!

    Can someone explain me why JS doesn't create array copy for every new
    instance but simply points to the same array? Of course I can create
    that array in constructor class like this

    var A = function() { this.r = [10]; }

    This works fine however if I do it in that way, hasOwnProperty will
    return TRUE for 'r' while doing it with prototype will return FALSE.
     
    Piotr K, Aug 24, 2009
    #1
    1. Advertising

  2. Piotr K wrote:
    > I came across a strange problem or I just don't understand how
    > prototype object works.. but first things first - take a look at this
    > code
    >
    > var A = function() {}
    >
    > A.prototype.r = [10];
    >
    > var a1 = new A, a2 = new A;
    >
    > a2.r[0] = 20;
    >
    > alert(a1.r[0]); // = 20 WTF ?!
    >
    > Can someone explain me why JS doesn't create array copy for every new
    > instance but simply points to the same array?


    Searching the prototype chain for your assignment will result in the
    property named `r' of the prototype object because you have not added a
    property named `r' to the object referred to by `a2' before. As a result,
    looking up the property named `r' of the object referred to by `a1' results
    in a reference to the same Array object, with the same property value that
    you have just set before.

    The prototype chain looks as follows:

    a1 ------> A.prototype ---> Object.prototype
    ^
    a2 --------'

    > Of course I can create that array in constructor class


    There are no classes. A constructor is a [[Construct]]able object.

    > like this
    >
    > var A = function() { this.r = [10]; }
    >
    > This works fine


    (But you should have delimited the outer assignment with `;', too.)

    Because then each individual object (as in constructor code, `this' refers
    to the object about to be constructed) has a (non-inherited) property named
    `r', and searching the prototype chain will result in a reference to the
    corresponding Array object that the property stores.

    > however if I do it in that way, hasOwnProperty will
    > return TRUE for 'r' while doing it with prototype will return FALSE.


    Works as designed.


    PointedEars
    --
    realism: HTML 4.01 Strict
    evangelism: XHTML 1.0 Strict
    madness: XHTML 1.1 as application/xhtml+xml
    -- Bjoern Hoehrmann
     
    Thomas 'PointedEars' Lahn, Aug 24, 2009
    #2
    1. Advertising

  3. Piotr K

    Piotr K Guest

    On 24 Sie, 03:34, Thomas 'PointedEars' Lahn <>
    wrote:
    > Piotr K wrote:
    > > I came across a strange problem or I just don't understand how
    > > prototype object works.. but first things first - take a look at this
    > > code

    >
    > > var A = function() {}

    >
    > > A.prototype.r = [10];

    >
    > > var a1 = new A, a2 = new A;

    >
    > > a2.r[0] = 20;

    >
    > > alert(a1.r[0]);   // = 20 WTF ?!

    >
    > > Can someone explain me why JS doesn't create array copy for every new
    > > instance but simply points to the same array?

    >
    > Searching the prototype chain for your assignment will result in the
    > property named `r' of the prototype object because you have not added a
    > property named `r' to the object referred to by `a2' before.  As a result,
    > looking up the property named `r' of the object referred to by `a1' results
    > in a reference to the same Array object, with the same property value that
    > you have just set before.
    >
    > The prototype chain looks as follows:
    >
    >   a1 ------> A.prototype ---> Object.prototype
    >              ^
    >   a2 --------'


    Thanks for detailed explanation, now it's clear to me however the
    question is how to resolve this? Is there any way to create copy of
    that array for each instance without adding it "manually" in
    constructor so hasOwnProperty will return FALSE? So far the only
    solution I see is creating smth like this:

    function hasOwnProperty(obj, key) {
    return (typeof obj.constructor.prototype[key] != 'undefined');
    }

    function copy(obj) {
    if(obj.constructor == Array) return obj.slice(0)
    [...]
    }

    var A = function() {
    for(var key in this.constructor.prototype) {
    if(this.constructor.prototype.hasOwnProperty(key)) {
    this[key] = copy(this.constructor.prototype[key]);
    }
    }
    }

    A.prototype.r = [10];

    Any other ideas?
     
    Piotr K, Aug 24, 2009
    #3
  4. Piotr K <> writes:

    > Thanks for detailed explanation, now it's clear to me however the
    > question is how to resolve this? Is there any way to create copy of
    > that array for each instance without adding it "manually" in
    > constructor so hasOwnProperty will return FALSE?


    Realistically, no (i.e., not without building your own framework inside
    the language). And why would you?
    You want each instance to have its own array, but you want
    hasOwnProperty to say that it doesn't.

    > So far the only
    > solution I see is creating smth like this:
    >
    > function hasOwnProperty(obj, key) {
    > return (typeof obj.constructor.prototype[key] != 'undefined');
    > }
    >
    > function copy(obj) {
    > if(obj.constructor == Array) return obj.slice(0)
    > [...]
    > }
    >
    > var A = function() {
    > for(var key in this.constructor.prototype) {
    > if(this.constructor.prototype.hasOwnProperty(key)) {
    > this[key] = copy(this.constructor.prototype[key]);
    > }
    > }
    > }
    >
    > A.prototype.r = [10];


    I.e., manually copying object properties from the prototype at
    creation time. That won't change how Object.prototype.hasOwnProperty
    reports it, but if you use your own hasOwnProperty, you can omit
    the copied properties.

    Still, why? What is the problem you are trying to solve?
    It feels very much like you are trying to solve a problem in one
    particular way instead of considering why it is a problem to begin
    with.

    /L
    --
    Lasse Reichstein Holst Nielsen
    'Javascript frameworks is a disruptive technology'
     
    Lasse Reichstein Nielsen, Aug 24, 2009
    #4
  5. Piotr K

    RobG Guest

    On Aug 24, 11:59 am, Piotr K <> wrote:
    > On 24 Sie, 03:34, Thomas 'PointedEars' Lahn <>
    > wrote:
    >
    >
    >
    >
    >
    > > Piotr K wrote:
    > > > I came across a strange problem or I just don't understand how
    > > > prototype object works.. but first things first - take a look at this
    > > > code

    >
    > > > var A = function() {}

    >
    > > > A.prototype.r = [10];

    >
    > > > var a1 = new A, a2 = new A;

    >
    > > > a2.r[0] = 20;

    >
    > > > alert(a1.r[0]);   // = 20 WTF ?!

    >
    > > > Can someone explain me why JS doesn't create array copy for every new
    > > > instance but simply points to the same array?

    >
    > > Searching the prototype chain for your assignment will result in the
    > > property named `r' of the prototype object because you have not added a
    > > property named `r' to the object referred to by `a2' before.  As a result,
    > > looking up the property named `r' of the object referred to by `a1' results
    > > in a reference to the same Array object, with the same property value that
    > > you have just set before.

    >
    > > The prototype chain looks as follows:

    >
    > >   a1 ------> A.prototype ---> Object.prototype
    > >              ^
    > >   a2 --------'

    >
    > Thanks for detailed explanation, now it's clear to me however the
    > question is how to resolve this?


    As Lasse said, without a clear explanation of what "this" is, it's
    difficult to suggest a fix.

    > Is there any way to create copy of
    > that array for each instance without adding it "manually" in
    > constructor so hasOwnProperty will return FALSE? So far the only
    > solution I see is creating smth like this:
    >

    [...]
    > Any other ideas?


    You can insert another object in the prototype chain using a maker
    function and give that object the r property, so you have:

    a1 --> dummy.prototype --> A.prototype ...

    During construction, add an r property to dummy.prototype so that each
    instance of A has an r property but hasOwnProperty('r') will return
    false.

    While that is possible, it seems like a solution looking for a
    problem.


    --
    Rob
     
    RobG, Aug 24, 2009
    #5
  6. Piotr K wrote:
    > Thanks for detailed explanation, now it's clear to me


    You are welcome.

    > however the question is how to resolve this? Is there any way to create
    > copy of that array for each instance without adding it "manually" in
    > constructor so hasOwnProperty will return FALSE?


    Mu.


    PointedEars
    --
    Anyone who slaps a 'this page is best viewed with Browser X' label on
    a Web page appears to be yearning for the bad old days, before the Web,
    when you had very little chance of reading a document written on another
    computer, another word processor, or another network. -- Tim Berners-Lee
     
    Thomas 'PointedEars' Lahn, Aug 24, 2009
    #6
  7. Piotr K

    Piotr K Guest

    > I.e., manually copying object properties from the prototype at
    > creation time. That won't change how Object.prototype.hasOwnProperty
    > reports it, but if you use your own hasOwnProperty, you can omit
    > the copied properties.
    >
    > Still, why? What is the problem you are trying to solve?
    > It feels very much like you are trying to solve a problem in one
    > particular way instead of considering why it is a problem to begin
    > with.


    What I want to do is iterate thru object properties and methods using
    "in" operator while ignoring all "built-in" members and to achieve
    this I need hasOwnProperty to return FALSE for these members - so this
    code:

    var A = function() {};

    A.prototype.r = [10, 20];

    var obj = new A;

    obj.x = 5;
    obj.y = 10;

    for(var key in obj) {
    if(obj.hasOwnProperty(key)) {
    document.write(key);
    }
    }

    Will return "x" "y".
     
    Piotr K, Aug 24, 2009
    #7
  8. Piotr K wrote:
    > What I want to do is iterate thru object properties and methods using

    ^^^^
    You should employ proper language forms here.

    > "in" operator while ignoring all "built-in" members and to achieve
    > this I need hasOwnProperty to return FALSE


    Probably you mean `false' (without quotes); ECMAScript implementations are
    case-sensitive.

    > for these members - so this code:
    >
    > var A = function() {};
    >
    > A.prototype.r = [10, 20];
    >
    > var obj = new A;
    >
    > obj.x = 5;
    > obj.y = 10;
    >
    > for(var key in obj) {


    That is _not_ using the `in' operator, but a for-in loop. One must
    distinguish carefully between `in' used in an expression (as an operator),
    and in a for-in statement.

    <http://PointedEars.de/es-matrix>

    > if(obj.hasOwnProperty(key)) {
    > document.write(key);
    > }
    > }
    >
    > Will return "x" "y".


    It is likely to _print_ "xy" (without quotes) to the document view. Your
    statement implies that you wish it to print "rxy" and the like there; you
    should simply remove the filtering `if' statement along with the
    hasOwnProperty() call then.


    PointedEars
    --
    Anyone who slaps a 'this page is best viewed with Browser X' label on
    a Web page appears to be yearning for the bad old days, before the Web,
    when you had very little chance of reading a document written on another
    computer, another word processor, or another network. -- Tim Berners-Lee
     
    Thomas 'PointedEars' Lahn, Aug 24, 2009
    #8
  9. Piotr K

    Piotr K Guest

    On 24 Sie, 15:37, Thomas 'PointedEars' Lahn <>
    wrote:
    > Piotr K wrote:
    > > What I want to do is iterate thru object properties and methods using

    >
    >                                ^^^^
    > You should employ proper language forms here.
    >
    > > "in" operator while ignoring all "built-in" members and to achieve
    > > this I need hasOwnProperty to return FALSE

    >
    > Probably you mean `false' (without quotes); ECMAScript implementations are
    > case-sensitive.
    >
    > > for these members - so this code:

    >
    > > var A = function() {};

    >
    > > A.prototype.r = [10, 20];

    >
    > > var obj = new A;

    >
    > > obj.x = 5;
    > > obj.y = 10;

    >
    > > for(var key in obj) {

    >
    > That is _not_ using the `in' operator, but a for-in loop.  One must
    > distinguish carefully between `in' used in an expression (as an operator),
    > and in a for-in statement.
    >
    > <http://PointedEars.de/es-matrix>
    >
    > >    if(obj.hasOwnProperty(key)) {
    > >            document.write(key);
    > >    }
    > > }

    >
    > > Will return "x" "y".

    >
    > It is likely to _print_ "xy" (without quotes) to the document view.  Your
    > statement implies that you wish it to print "rxy" and the like there; you
    > should simply remove the filtering `if' statement along with the
    > hasOwnProperty() call then.


    I wish to print "xy" but also have copy of "r" for each instance which
    can't be achieved using "prototype" so I need to assign it in
    constructor but then it will print "rxy" (cause hasOwnProperty will
    return TRUE for "r"). In other words - I want "r" as a "built-in"
    member.
     
    Piotr K, Aug 24, 2009
    #9
  10. On Sun, 23 Aug 2009 at 18:09:48, in comp.lang.javascript, Piotr K wrote:
    >I came across a strange problem or I just don't understand how
    >prototype object works.. but first things first - take a look at this
    >code
    >
    >var A = function() {}
    >
    >A.prototype.r = [10];
    >
    >var a1 = new A, a2 = new A;
    >
    >a2.r[0] = 20;
    >
    >alert(a1.r[0]); // = 20 WTF ?!
    >
    >Can someone explain me why JS doesn't create array copy for every new
    >instance but simply points to the same array?


    Because javascript is not a conventional prototype-based language. Nor
    is it a conventional class definition-based language. In fact,
    javascript is pretty much on its own.


    > Of course I can create
    >that array in constructor class like this
    >
    >var A = function() { this.r = [10]; }
    >
    >This works fine however if I do it in that way, hasOwnProperty will
    >return TRUE for 'r' while doing it with prototype will return FALSE.


    It's badly named.
    hasOwnProperty
    is really
    isIndependentProperty
    where what you would like is
    isPropertyAddedAfterConstruction

    You can emulate this quite easily. Just give the objects a special
    property to hold all the properties added later, as in

    var obj = new A;

    obj.added.x = 5;
    obj.added.y = 10;

    for(var key in obj.added)
    {
    if(obj.added.hasOwnProperty(key))
    ...
    }

    John
    --
    John Harris
     
    John G Harris, Aug 24, 2009
    #10
  11. Piotr K wrote:
    > Thomas 'PointedEars' Lahn wrote:
    >> Piotr K wrote:
    >>> if(obj.hasOwnProperty(key)) {
    >>> document.write(key);
    >>> }
    >>> }
    >>> Will return "x" "y".

    >> It is likely to _print_ "xy" (without quotes) to the document view. Your
    >> statement implies that you wish it to print "rxy" and the like there; you
    >> should simply remove the filtering `if' statement along with the
    >> hasOwnProperty() call then.

    >
    > I wish to print "xy" but also have copy of "r" for each instance which
    > can't be achieved using "prototype" so I need to assign it in
    > constructor but then it will print "rxy" (cause hasOwnProperty will
    > return TRUE for "r"). In other words - I want "r" as a "built-in"
    > member.


    There are no members, there are properties. There are no classes, there is
    a prototype chain. And there is no spoon.

    Your question reads to me like "Can I make a cat sound like a dog?" And the
    answer that you apparently want to hear is "Yes, you can, if you augment the
    cat's central nervous system with a synthesizer that recognizes the signal
    for the meow and puts out a bark instead."¹

    Please trim your quotes to the necessary minimum required to retain context.

    <http://jibbering.com/faq/#posting>


    PointedEars
    ___________
    ¹ Kids, *please* don't try this at home!
    --
    Prototype.js was written by people who don't know javascript for people
    who don't know javascript. People who don't know javascript are not
    the best source of advice on designing systems that use javascript.
    -- Richard Cornford, cljs, <f806at$ail$1$>
     
    Thomas 'PointedEars' Lahn, Aug 24, 2009
    #11
  12. On Mon, 24 Aug 2009 at 13:09:08, in comp.lang.javascript, kangax wrote:
    >John G Harris wrote:
    >> On Sun, 23 Aug 2009 at 18:09:48, in comp.lang.javascript, Piotr K wrote:

    >[...]
    >>> Of course I can create
    >>> that array in constructor class like this
    >>>
    >>> var A = function() { this.r = [10]; }
    >>>
    >>> This works fine however if I do it in that way, hasOwnProperty will
    >>> return TRUE for 'r' while doing it with prototype will return FALSE.

    >> It's badly named.
    >> hasOwnProperty
    >> is really
    >> isIndependentProperty

    >
    >In which sense is it independent? I think "own" describes property
    >relation to an object quite well.


    I was thinking its value can be assigned independently of all other
    objects, which is true. Unfortunately, if the value is an object the
    object might also be the value of some other object property. Neither
    'own' nor 'independent' are completely suitable for javascript :-(

    John
    --
    John Harris
     
    John G Harris, Aug 24, 2009
    #12
  13. John G Harris wrote:
    > On Sun, 23 Aug 2009 at 18:09:48, in comp.lang.javascript, Piotr K wrote:
    >> I came across a strange problem or I just don't understand how
    >> prototype object works.. but first things first - take a look at this
    >> code
    >>
    >> var A = function() {}
    >>
    >> A.prototype.r = [10];
    >>
    >> var a1 = new A, a2 = new A;
    >>
    >> a2.r[0] = 20;
    >>
    >> alert(a1.r[0]); // = 20 WTF ?!
    >>
    >> Can someone explain me why JS doesn't create array copy for every new
    >> instance but simply points to the same array?

    >
    > Because javascript is not a conventional prototype-based language. Nor
    > is it a conventional class definition-based language. In fact,
    > javascript is pretty much on its own.
    >
    >
    >> Of course I can create
    >> that array in constructor class like this
    >>
    >> var A = function() { this.r = [10]; }
    >>
    >> This works fine however if I do it in that way, hasOwnProperty will
    >> return TRUE for 'r' while doing it with prototype will return FALSE.

    >
    > It's badly named.
    > hasOwnProperty
    > is really
    > isIndependentProperty
    > where what you would like is
    > isPropertyAddedAfterConstruction
    >



    Independent would seem to mean "owned or controlled by nothing else".

    That definition what other objects in the objects prototype chain may
    not have.

    The problem with that is that it is different from "hasOwnProperty".
    Method hasOwnProperty means that the object has a property with that
    name. It doesn't say that a property exists in the prototype chain, but
    it does not preclude that possibliity.

    A constructor's prototype is useful for shared behavior as well as
    default property values. An example default instance properties in the
    prototype:

    function Animation(duration) {
    if (typeof duration == "number")
    this.duration = duration * 1000; // default 1 sec.
    this.timeLimit = this.duration; // for SeekTo()
    }

    Animation.prototype = {
    duration : 1000
    // shared behavior, etc.
    };


    var a = new Animation;
    a.duration; // 1000
    a.hasOwnProperty("duration"); // false.
    a.duration = 2000;
    a.hasOwnProperty("duration"); // true.
    delete a.duration; // true;
    a.hasOwnProperty("duration"); //false
    a.duration; // 1000

    When [[Get]] is called on that Animation "instance", the - duration -
    property is found in the prototype chain.

    When [[Put]] is called on that object, the property is added to the
    objecdt itself.

    > You can emulate this quite easily. Just give the objects a special
    > property to hold all the properties added later, as in
    >


    Yes, a separate, plain old object for those that can be enumerated would
    be a simple approach.

    [snip example]

    Garrett
    --
    comp.lang.javascript FAQ: http://jibbering.com/faq/
     
    Garrett Smith, Aug 24, 2009
    #13
  14. On Aug 25, 5:20 am, Thomas 'PointedEars' Lahn <>
    wrote:

    > Your question reads to me like "Can I make a cat sound like a dog?"  And the
    > answer that you apparently want to hear is "Yes, you can, if you augment the
    > cat's central nervous system with a synthesizer that recognizes the signal
    > for the meow and puts out a bark instead."¹


    [OT] Apologies in advance for the offence caused:

    Q: How do you make a dog meow?

    A: Freeze it and cut it in half with a chainsaw.

    Q: How do you make a cat woof?

    A: Dunk it in petrol and light it on fire.
     
    Hamish Campbell, Aug 25, 2009
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. June Lee
    Replies:
    2
    Views:
    811
    Jim Cobban
    Apr 13, 2008
  2. Philipp
    Replies:
    21
    Views:
    1,140
    Philipp
    Jan 20, 2009
  3. Replies:
    9
    Views:
    206
    Thomas 'PointedEars' Lahn
    May 26, 2006
  4. Replies:
    3
    Views:
    273
  5. javascript fish
    Replies:
    0
    Views:
    177
    javascript fish
    Oct 11, 2008
Loading...

Share This Page