1

solution

I am still getting the hang of it, and its probally logic for a lot of you. But I've updated the post with how I got it working, might some one come here by search.

declare:

var test=Element({"id" : 1, "name" : "wrapper"}).
      append(Element({"id" : 2, "name" : "elm A"}),
             Element({"id" : 3, "name" : "elm b"})
      );

alert(test.getInfo("name"));
alert(test.aArguments["children"][1].getInfo("name"));

'class':

var Element = function ($aPassArguments) {
    aArguments: {
            "id" : false,
            "name" : false,
            "type" : false,
            "title" : false, 
            "style" : false,
            "action" : [],
            "parent" : false,
            "children" : []
        };
    for (var prop in this.aArguments)
            if (prop in $aPassArguments) 
                this.aArguments[prop] = $aPassArguments[prop];
    return {
        append: function () {
            $argList = arguments;
            for ($i = 0; $i < $argList.length; $i++)
                if (typeof $argList[$i]=="string")
                    this.setChild(this.importDB($argList[$i],true));
                else
                    this.setChild($argList[$i]);
        },
         setChild: function($oChild) {
            this.aArguments["children"][this.aArguments["children"].length]=$oChild; 
        }
    };
};

.............................................................

Previous edit

I wasnt aware a new object instance in javascript is a reference instead of a copy. Now I want to have a copy of my own object Element. Apperantly (thanks @blurd) I want it to be a factory hybrid: http://javascript.info/tutorial/factory-constructor-pattern

Thanks to the help of @blurd and me defining some problems, I came up with a sollution like the following:

(but I am not happying with my usage declaration below)

In which I finaly got copies of my Element object instead of references. The good answers below didnt completly solve my problem. But this is due to my poor clarification and understanding of the problems

Sort of solution

var Element = function (initialConfig) {

    return {
        aArguments: {
            "id" : false,
            "name" : false,
            "type" : false,
            "title" : false, 
            "style" : false,
            "action" : [],
            "parent" : false,
            "children" : [],
        },


        create:function ($aPassArguments) {
            for (var prop in this.aArguments)
                if (prop in $aPassArguments) 
                    this.aArguments[prop] = $aPassArguments[prop];
        },
        append: function () {
            $argList = arguments;
            for ($i = 0; $i < $argList.length; $i++)
                if (typeof $argList[$i]=="string")
                    this.setChild(this.importDB($argList[$i],true));
                else
                    this.setChild($argList[$i]);
        },
         setChild: function($oChild) {
            this.aArguments["children"][this.aArguments["children"].length]=$oChild; 
        }
    };
};

usage

var test=Element();
test.create({"id" : 1, "name" : "wrapper"});
var test2=Element();
test2.create({"id" : 2, "name" : "elm A"});
test3.create({"id" : 3, "name" : "elm B"});
test.append(test2,test3);

alert(test.aArguments["name"]);
alert(test.aArguments["children"][0].aArguments["name"]);

Now I am very unhappy about the usage,I would like it be one line and use a constructor again. And this is probally possible, and... after some more selfschooling I will probally solve it. But for now I am done with it :P just updated my post with this. When I get to it again and have a beter declaration I will update it again. And perhaps someone might share a way (beter way) to do this. To eventually have something like this:

var test=new Element({"id" : 3, "name" : "wrapper"})
           .append( new Element{"id" : 3, "name" : "elm A"}), 
                    new Element({"id" : 3, "name" : "elm B"}) 
                  );

.............................................................................................

old post

I am pulling my hair outs here, everything I search about javascript and objects tells me the same, which is not enough, because I cant figure out why the following code isnt working propaly:

For example I am making an object like this:

var Element = {
    aArguments: {                                                       //set Default arguments
        "id" : false,
        "name" : false,
        "type" : false,
        "title" : false, 
        "style" : false,
        "action" : [],
        "parent" : false,
        "children" : {},
    },
    create:function ($aPassArguments) {
        for (var prop in this.aArguments)
            if (prop in $aPassArguments) 
                this.aArguments[prop] = $aPassArguments[prop];
        return this;
    },
    append: function () {
        $argList = arguments;
        for ($i = 0; $i < $argList.length-1; $i++)
            if (typeof $argList[$i]=="string")
                this.setChild(this.importDB($argList[$i],true));
            else
                this.setChild($argList[$i]);
        return this;
    },
    setChild: function($oChild) {
        this.aArguments["children"][this.aArguments["children"].length-1]=$oChild; 
    },
    getInfo: function($sKey) {
        return this.aArguments[$sKey];
    }
};

Which merges $aPassArguments with this.Arguments on calling of .create() (I cant figureif its possible to use a '__constructor'). To replace given proparties in aArguments.

And add passed object(s) with .append to aArguments["childeren"].

But when I call the object like this:

$set=(Element.create({"id": 1, "name" : "wrapper"})).
     append(Element.create({"id" : 3, "name" : "elm A"}));
alert($set.getInfo("name"));

It will alert me "Elm A" and not "wrapper".

I assume that this is because I am not creating a new object of Element, but are working on the same object. Now to me the logical solution and start would be to write:

$set=(new Element.create({"id": 1, "name" : "wrapper"})).
     append(new Element.create({"id" : 3, "name" : "elm A"}));
alert($set.getInfo("name"));

but I get the error: TypeError: (intermediate value).append is not a function

Why isnt my code not working as supposed by me? And is it possible and if so how do I add a constructor to an object? So I could skip calling .create and use:

 $set=new Element({"id": 1, "name" : "wrapper"}).
     append(new Element({"id" : 3, "name" : "elm A"}));
058WistWol
  • 89
  • 7

2 Answers2

1

You are right, you should be using the new operator. Aside from that, it looks like you're trying to make this some type of factory hybrid. I suggest the following.

Use a Constructor Function

Include an optional configuration that you can use when creating the object.

var Element = function (initialConfig) {
    if (initialConfig) {
        this.create(initialConfig);
    }
};

Add to the Prototype

All your shared Element members should be part of the prototype.

Element.prototype = {
    aArguments: {
        "id" : false,
        "name" : false,
        "type" : false,
        "title" : false, 
        "style" : false,
        "action" : [],
        "parent" : false,
        "children" : {},
    },
    create:function ($aPassArguments) {
        for (var prop in this.aArguments)
            if (prop in $aPassArguments) 
                this.aArguments[prop] = $aPassArguments[prop];
        return this;
    },
    append: function () {
        $argList = arguments;
        for ($i = 0; $i < $argList.length-1; $i++)
            if (typeof $argList[$i]=="string")
                this.setChild(this.importDB($argList[$i],true));
            else
                this.setChild($argList[$i]);
        return this;
    },
    setChild: function($oChild) {
        this.aArguments["children"][this.aArguments["children"].length-1]=$oChild; 
    },
    getInfo: function($sKey) {
        return this.aArguments[$sKey];
    }
};

Examples

Your examples should now work as you expected. Notice that you can't call new Element.create() as that would treat Element.create as a constructor. Instead, pass your initial values into the constructor.

$set = new Element({"id": 1, "name" : "wrapper"}).
     append(new Element({"id" : 3, "name" : "elm A"}));

alert($set.getInfo("name"));

Be Careful

You're not checking for own properties in your loops, omitting {}, and I spotted at least one implied global. JavaScript will bite you if you're not careful. Consider using JSLint or JSHint to help you spot these problems.

reergymerej
  • 2,371
  • 2
  • 26
  • 32
  • Well your example isnt working as supposed to (it still alert elm A instead of wrapper), but your reply is usefull. – 058WistWol Feb 28 '14 at 13:26
  • It's not clear what you're trying to do. Can you edit your question? – reergymerej Feb 28 '14 at 13:30
  • 1
    `append` tries to add a child, but you're using `this.aArguments["children"].length-1`. There is no `length` property on objects, so this results in `NaN`. – reergymerej Feb 28 '14 at 13:32
  • Thanks again @blurd The problem probaly comes from my own code. Your example is great. And I need to solve my own problems, but if you want to know. I want to create an element object which has element objects as childeren. In my example coding I want the alert of the name to be "wrapper" because this is the parent, but it alert "elm A" which is supposed to be a child. And be to honest I dont know why I put a "return this in .append", that should be removed. But when I do that $set doesnt have the method .getInfo. Thus in short: it seems like .append overwrites the parent element – 058WistWol Feb 28 '14 at 13:40
  • to be honest @blurd I still cant figure it out. The structure in your example is beter, but the result is still the same. The: "return this;" shouldnt be in .append() And: "this.aArguments["children"].length-1" doesnt work and should be done differently (I google this myself for selfschooling :P) But it seems that .append(new Element...) overwrites the previous object Element set to $set. Why is this? I is it me or does this seem unlogical? (I get me a coffee since its probally me :P) – 058WistWol Feb 28 '14 at 13:52
  • in short: `$set = new Element({"id": 1, "name" : "wrapper"}); new Element({"id" : 3, "name" : "elm A"}); alert($set.getInfo("name"));` Alert "elm A" and not "wrapper". I want $set to be a refference and not a copy of the object Element (I hope I use the right terms, english is not my first nor second lang and I am not sure of it all :P) – 058WistWol Feb 28 '14 at 14:03
  • http://stackoverflow.com/questions/728360/most-elegant-way-to-clone-a-javascript-object This probs answers that for me. Any way thank you again for your efforts and time – 058WistWol Feb 28 '14 at 14:07
1

Your create function does not create any object, but rather changes on place the Element. aArguments object. Any strange thing might follow.
Anyway, just go for a clean and simple prototypal inheritance scheme, do not use $, remember to always declare your vars, and keep things simple :

function Element(initialValues) {
    this.id = this.prototype.id++;
    this.name = null;
    this.type = null;
    this.title = null;
    this.style = null;
    this.action = [];
    this.parent = null;
    this.children = [];
    for (var prop in initialValues)
        if (this[prop] != undefined) this[prop] = initialValues[prop];
}

Element.prototype = {
    append: function () {
        for (var i = 0; i < arguments.length - 1; i++) {
            var thisElement = arguments[i];
            if (typeof thisElement == "string") this.setChild(this.importDB(thisElement, true));
            else this.setChild(thisElement);
        }
        return this;
    },
    setChild: function (child) {
        this.children.push(child);
        return this;
    },
    getInfo: function (key) {
        return this[Key];
    },
    id: 0
};
GameAlchemist
  • 18,995
  • 7
  • 36
  • 59
  • Thanks that clears it up for me :) I am a bit rusty in coding and new to doing anything javascript. Btw why not use $? I am used to always declare a var with a dollar sign. I ll google this now, but just sharing my wonder – 058WistWol Feb 28 '14 at 13:08
  • There are quite a few traps in Javascript, that why i quite prefer Dart which just as compatible but far less complicated. If you happen to stick to js, find your design style and stick to it, because there are always 10 ways to do something in js. Happy coding ! – GameAlchemist Feb 28 '14 at 13:12
  • `$` is only *needed* for PHP. `$` in JS implies that it's a jQuery or Angular object. – reergymerej Feb 28 '14 at 13:26