Different 'instances' of the same kind keep different variables, but their arrays are common?

I'm a bit surprised at this, but I can't say if it is a general JavaScript thing, or an Enyo issue.
Say, I have a kind which is used twice as a component in a parent kind. The variables inside these two components, whether they are published or not, live their own separate lives, except if the variable happens to be an array. In that case changes to the array done by the one component, gets mirrored in the array in the other component as well.

See http://jsfiddle.net/SPLzu/ which contains this code:
enyo.kind({
    name: "App",
    components: [   
        {kind: "compo", name: "compoOne", content: "First start counting",},
        {kind: "compo", name: "compoTwo", content: "Second start counting"}
    ]
});

enyo.kind({
    name: "compo",
    propArray: [],
    propNumber: 0,
    handlers: {
        "ontap": "changeContent"
    },
    published: {
        "publArray": [],
        "publnumber": 0
    },
    changeContent: function() {
        this.propArray.push(this.propNumber);
        this.propNumber=this.propNumber+1;
        this.setContent(this.propArray.toString())
    }
});
If you click on these two different components, you see that 'propNumber' changes independent from clicks on the other component, but 'propArray' is in fact affected by clicks on the other component.

Anyone know anything to comment on this? If I would want to have the arrays to act independent, how could I make this happen? At this moment I don't have an immediate problem with this, but I noticed this when I was debugging an app, and I was surprised to see this. I imagine that at a later stage I would like to have independent arrays in different instances.

Comments

  • Yes, this is because arrays and objects in JavaScript are stored in properties by reference. So if you say "foo.a = [1, 2, 3]; bar.b = foo.a;" both foo.a and bar.b refer to the same array.

    If you want a local instance of an object or array as a property of your kind instances, we recommend that you instead set that in your create method. So for this kind, instead of saying propArray: [],, you'd have this
    
        create: function() {
            this.inherited(arguments);
            this.propArray = [];
        },
    
    where you ensure each instance has its own new array to use.

    (To be a little more technical, until you assign to your local property in an instance, even for simple values, you're actually using the copy that's in the shared prototype object, so your ref to this.propNumber is actually to this.prototype.propNumber; that holds until you assign, so saying this.propNumber = 42 means that a propNumber property is created on your instance that shadows the original value in the prototype.)
  • Alright, that's interesting. I will definitely keep this in mind, because with the way I'm working - reusing kinds with different variables - I will face this problem. Thanks a lot for your accurate answer, Ben!
  • @MrPleasant, typically, if you need instance-level arrays/objects you can assign them in your constructor rather than on the base kind. See a quick example https://gist.github.com/clinuz/ed0ca11492b6f65fca6e.
  • Thanks for the suggestion, Clinuz! What exactly is the difference between the constructor that you use and the create function that unwiredben suggestion? They both seem very much alike to me. Or is it more like how this kind of thing is usually done?
  • constructor is part of the base Enyo OOP system and available on any kind. create() is a method added by enyo.Component and available on any kind derived from that. The reason for the two different methods is that constructor() is actually used to implement the whole component system.
  • Thank you, I think that is clear now!
Sign In or Register to comment.